Sửa đổi phản hồi HTTP từ tiện ích mở rộng của Chrome


83

Có thể tạo tiện ích mở rộng Chrome sửa đổi các phần tử phản hồi HTTP không?

Tôi đã xem xét các API tiện ích mở rộng của Chrome , nhưng tôi không tìm thấy bất kỳ thứ gì để thực hiện việc này.


1
Nói chung, không. Xem https://code.google.com/p/chromium/issues/detail?id=104058 . Đối với một tập hợp con các trường hợp sử dụng, có. Bạn có thể giải thích lý do tại sao bạn muốn chỉnh sửa nội dung phản hồi không?
Rob W

được rồi cảm ơn. hãy viết nó như một câu trả lời và tôi sẽ chấp nhận điều đó.
Captain dragon,

Nếu bạn chấp nhận các trình duyệt khác, thì Firefox sẽ hỗ trợ webRequest.filterResponseData(). Thật không may, đây là giải pháp chỉ dành cho Firefox.
Franklin Yu

Câu trả lời:


49

Nói chung, bạn không thể thay đổi nội dung phản hồi của một yêu cầu HTTP bằng các API tiện ích mở rộng Chrome tiêu chuẩn.

Tính năng này đang được yêu cầu tại 104058: API WebRequest: cho phép tiện ích mở rộng chỉnh sửa nội dung phản hồi . Gắn dấu sao vấn đề để nhận thông báo về các bản cập nhật.

Nếu bạn muốn chỉnh sửa nội dung phản hồi cho một mã đã biết XMLHttpRequest, hãy chèn mã qua tập lệnh nội dung để ghi đè phương thức XMLHttpRequestkhởi tạo mặc định bằng phương thức xây dựng tùy chỉnh (đầy đủ tính năng) ghi lại phản hồi trước khi kích hoạt sự kiện thực. Đảm bảo rằng đối tượng XMLHttpRequest của bạn hoàn toàn tuân thủ với đối tượng tích hợp sẵn của Chrome XMLHttpRequest, nếu không các trang web nặng AJAX sẽ bị hỏng.

Trong các trường hợp khác, bạn có thể sử dụng chrome.webRequesthoặc chrome.declarativeWebRequestcác API để chuyển hướng yêu cầu đến data:-URI. Không giống như cách tiếp cận XHR, bạn sẽ không nhận được nội dung ban đầu của yêu cầu. Trên thực tế, yêu cầu sẽ không bao giờ được gửi đến máy chủ vì việc chuyển hướng chỉ có thể được thực hiện trước khi yêu cầu thực sự được gửi đi. Và nếu bạn chuyển hướng một main_frameyêu cầu, người dùng sẽ thấy data:-URI thay vì URL được yêu cầu.


1
Tôi không nghĩ rằng dữ liệu: Ý tưởng -URI hoạt động. Tôi vừa cố gắng làm điều này và có vẻ như CORS chặn nó. Trang đưa ra yêu cầu ban đầu kết thúc với nội dung: "Yêu cầu đã được chuyển hướng đến 'data: text / json;, {...}', không được phép đối với các yêu cầu có nguồn gốc chéo yêu cầu chuyển hướng trước".
Joe

@Joe Không thể tái tạo trong Chromium 39.0.2171.96
Rob W

1
@RobW, Một số thủ thuật hoặc giải pháp để ngăn URL chuyển thành là data:text...gì?
Pacerier

1
@Pacerier Thực sự không có một giải pháp thỏa đáng. Trong câu trả lời của tôi, tôi đã đề cập đến tùy chọn sử dụng tập lệnh nội dung để thay thế nội dung, nhưng ngoài việc bạn không thể "sửa đổi" phản hồi mà không làm thay đổi URL.
Rob W

1
Tôi đã thử giải pháp này. Lưu ý rằng bạn có thể cần ghi đè tìm nạp () bên cạnh XMLHttpRequest. giới hạn là các yêu cầu của trình duyệt đối với js / images / css không bị chặn.
user861746

27

Tôi vừa phát hành một tiện ích mở rộng Devtools làm được điều đó :)

Nó được gọi là giả mạo, dựa trên mitmproxy và nó cho phép bạn xem tất cả các yêu cầu được thực hiện bởi tab hiện tại, sửa đổi chúng và phục vụ phiên bản đã sửa đổi vào lần tiếp theo bạn làm mới.

Đây là một phiên bản khá sớm nhưng nó phải tương thích với OS X và Windows. Hãy cho tôi biết nếu nó không hiệu quả với bạn.

Bạn có thể lấy nó tại đây http://dutzi.github.io/tamper/

Cách thức hoạt động

Như @Xan đã nhận xét bên dưới, tiện ích mở rộng giao tiếp thông qua Nhắn tin gốc với một tập lệnh python mở rộng mitmproxy .

Tiện ích mở rộng liệt kê tất cả các yêu cầu sử dụng chrome.devtools.network.onRequestFinished.

Khi bạn nhấp vào các yêu cầu, nó sẽ tải xuống phản hồi của nó bằng cách sử dụng getContent()phương thức của đối tượng yêu cầu , sau đó gửi phản hồi đó đến tập lệnh python để lưu nó cục bộ.

Sau đó, nó mở tệp trong trình chỉnh sửa (sử dụng callcho OSX hoặc subprocess.Popencho windows).

Tập lệnh python sử dụng mitmproxy để lắng nghe tất cả các giao tiếp được thực hiện thông qua proxy đó, nếu nó phát hiện yêu cầu đối với tệp đã được lưu, nó sẽ phân phối tệp đã được lưu thay thế.

Tôi đã sử dụng API proxy của Chrome (cụ thể chrome.proxy.settings.set()) để đặt PAC làm cài đặt proxy. Tệp PAC đó chuyển hướng tất cả giao tiếp đến proxy của tập lệnh python.

Một trong những điều tuyệt vời nhất về mitmproxy là nó cũng có thể sửa đổi giao tiếp HTTP. Vì vậy, bạn cũng có cái đó :)


Giải pháp thú vị, mặc dù nó yêu cầu một mô-đun Native Host.
Xan

5
Nhân tiện, nó sẽ hữu ích nếu bạn giải thích rõ hơn về kỹ thuật được sử dụng ở đây.
Xan

9
tiện ích mở rộng Devtools thú vị! Tuy nhiên có vẻ như người duy nhất có thể thay đổi phản ứng tiêu đề và không phải là phản ứng cơ thể với Tamper.
Michael Trouw

3
Sự cố với cài đặt.
Dmitry Pleshkov

1
Chúng ta có thể sửa đổi nội dung phản hồi với điều này không?
Kiran

17

Đúng. Có thể thực hiện được với chrome.debuggerAPI, cấp quyền truy cập mở rộng vào Giao thức Chrome DevTools , hỗ trợ chặn và sửa đổi HTTP thông qua API mạng của nó .

Giải pháp này được đề xuất bởi một nhận xét trên Chrome Issue 487422 :

Đối với bất kỳ ai muốn có một giải pháp thay thế có thể thực hiện được vào lúc này, bạn có thể sử dụng chrome.debuggertrong trang nền / sự kiện để đính kèm vào tab cụ thể mà bạn muốn nghe (hoặc đính kèm vào tất cả các tab nếu có thể, chưa kiểm tra tất cả các tab) , sau đó sử dụng API mạng của giao thức gỡ lỗi.

Vấn đề duy nhất với điều này là sẽ có thanh màu vàng thông thường ở đầu khung nhìn của tab, trừ khi người dùng tắt nó đi chrome://flags.

Đầu tiên, đính kèm trình gỡ lỗi vào đích:

chrome.debugger.getTargets((targets) => {
    let target = /* Find the target. */;
    let debuggee = { targetId: target.id };

    chrome.debugger.attach(debuggee, "1.2", () => {
        // TODO
    });
});

Tiếp theo, gửi Network.setRequestInterceptionEnabledlệnh, lệnh này sẽ cho phép chặn các yêu cầu mạng:

chrome.debugger.getTargets((targets) => {
    let target = /* Find the target. */;
    let debuggee = { targetId: target.id };

    chrome.debugger.attach(debuggee, "1.2", () => {
        chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });
    });
});

Chrome bây giờ sẽ bắt đầu gửi Network.requestInterceptedsự kiện. Thêm người nghe cho họ:

chrome.debugger.getTargets((targets) => {
    let target = /* Find the target. */;
    let debuggee = { targetId: target.id };

    chrome.debugger.attach(debuggee, "1.2", () => {
        chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });
    });

    chrome.debugger.onEvent.addListener((source, method, params) => {
        if(source.targetId === target.id && method === "Network.requestIntercepted") {
            // TODO
        }
    });
});

Trong người nghe, params.requestsẽ là Requestđối tượng tương ứng .

Gửi phản hồi với Network.continueInterceptedRequest:

  • Chuyển mã hóa base64 của phản hồi thô HTTP mong muốn của bạn ( bao gồm dòng trạng thái HTTP, tiêu đề, v.v. ) dưới dạng rawResponse.
  • Vượt qua params.interceptionIdnhư interceptionId.

Lưu ý rằng tôi chưa thử nghiệm bất kỳ điều nào trong số này.


Có vẻ rất hứa hẹn, mặc dù tôi đang thử nó ngay bây giờ (Chrome 60) và tôi thiếu thứ gì đó hoặc vẫn không thể; các setRequestInterceptionEnabledphương pháp dường như không được bao gồm trong v1.2 DevTools giao thức, và tôi không thể tìm thấy một cách để gắn nó với (tip-of-cây) phiên bản mới nhất để thay thế.
Aioros

1
Tôi đã thử giải pháp này và nó hoạt động ở một mức độ nào đó. Nếu bạn muốn sửa đổi yêu cầu, giải pháp này là tốt. Nếu bạn muốn sửa đổi phản hồi dựa trên phản hồi trả về của máy chủ, không có cách nào. không có phản hồi tại điểm đó. của coz bạn có thể ghi đè trường rawresponse như tác giả đã nói.
user861746

1
chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });không thành công với 'Network.setRequestInterceptionEnabled' không được tìm thấy '
Pacerier

1
@ MultiplyByZer0, Ok quản lý để làm cho nó hoạt động. i.stack .
Pacerier

@Pacerier Bạn nói đúng rằng giải pháp này không lý tưởng, nhưng tôi không biết giải pháp nào tốt hơn. Ngoài ra, như bạn đã nhận thấy, câu trả lời này chưa đầy đủ và cần được cập nhật. Tôi sẽ làm điều đó sớm, hy vọng.
MultiplyByZer0

12

Giống như @Rob w đã nói, tôi đã ghi đè XMLHttpRequestvà đây là kết quả để sửa đổi bất kỳ yêu cầu XHR nào trong bất kỳ trang web nào (hoạt động giống như proxy sửa đổi minh bạch):

var _open = XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function (method, URL) {
    var _onreadystatechange = this.onreadystatechange,
        _this = this;

    _this.onreadystatechange = function () {
        // catch only completed 'api/search/universal' requests
        if (_this.readyState === 4 && _this.status === 200 && ~URL.indexOf('api/search/universal')) {
            try {
                //////////////////////////////////////
                // THIS IS ACTIONS FOR YOUR REQUEST //
                //             EXAMPLE:             //
                //////////////////////////////////////
                var data = JSON.parse(_this.responseText); // {"fields": ["a","b"]}

                if (data.fields) {
                    data.fields.push('c','d');
                }

                // rewrite responseText
                Object.defineProperty(_this, 'responseText', {value: JSON.stringify(data)});
                /////////////// END //////////////////
            } catch (e) {}

            console.log('Caught! :)', method, URL/*, _this.responseText*/);
        }
        // call original callback
        if (_onreadystatechange) _onreadystatechange.apply(this, arguments);
    };

    // detect any onreadystatechange changing
    Object.defineProperty(this, "onreadystatechange", {
        get: function () {
            return _onreadystatechange;
        },
        set: function (value) {
            _onreadystatechange = value;
        }
    });

    return _open.apply(_this, arguments);
};

ví dụ: mã này có thể được sử dụng thành công bởi Tampermonkey để thực hiện bất kỳ sửa đổi nào trên bất kỳ trang web nào :)


1
Tôi đã sử dụng mã của bạn và nó ghi lại lỗi được bắt trên bảng điều khiển, nhưng nó không thay đổi phản hồi mà ứng dụng của tôi nhận được (Angular).
André Roggeri Campos

2
@ AndréRoggeriCampos Tôi cũng gặp phải điều tương tự. Sử dụng góc mới hơn responsechứ không phải responseText, vì vậy tất cả các bạn phải làm là thay đổi Object.defineProperty để sử dụng responsethay vì
Jonathan Gawrych

Cảm ơn rât nhiều ! nó hoạt động trên tiện ích mở rộng chrome của tôi!
Lancer.Yan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.