笔者在项目开发中有需求,需要拦截 js中 发起的 http 请求和响应数据 写到文件中,方便给开发人员或者测试人员查看。笔者拿到这个需求第一反应是,cef肯定有这种接口可供我们使用,所以肯定能实现咯。这里笔者用的是cef2623版本。
笔者百度了一下 大致可以在 CefRequestHandler的回调函数可以得到一些东西,一开始 笔者找到的最相近的方法是 下面这个函数OnResourceLoadComplete,既有request 又有response。
///
// Called on the IO thread when a resource load has completed. |request| and
// |response| represent the request and response respectively and cannot be
// modified in this callback. |status| indicates the load completion status.
// |received_content_length| is the number of response bytes actually read.
///
/*--cef()--*/
virtual void OnResourceLoadComplete(CefRefPtr browser,
CefRefPtr frame,
CefRefPtr request,
CefRefPtr response,
URLRequestStatus status,
int64 received_content_length) {}
结果空欢喜一场。我们可以通过request和response指针能 拿到请求头和请求体 和 响应头 响应状态码等 但就是得不到 响应体!
所以 百度不行,当然谷歌了呀。虽然没有得到具体代码提示,但是提示说在 示例程序中有,恍然大悟了 应该回归初心 ,有什么需求或者问题 都可以看cef示例工程。在cefclient有拦截request请求和响应的例子!
笔者需求当然实现了,由于是项目代码 这里不便展示。就把cefclient 中怎么处理的给大家说说。
这里直接说答案,要想获取 http response的响应体,应该在这个回调函数里面做处理。下面处理是在cefclient示例工程的test_runner.cc文件中的这个函数。
CefRefPtr ClientHandler::GetResourceResponseFilter(
CefRefPtr browser,
CefRefPtr frame,
CefRefPtr request,
CefRefPtr response) {
CEF_REQUIRE_IO_THREAD();
return test_runner::GetResourceResponseFilter(browser, frame, request,
response);
}
大家继续跟代码,跟踪到response_filter_test.cc文件下的下面这函数。
CefRefPtr GetResourceResponseFilter(
CefRefPtr browser,
CefRefPtr frame,
CefRefPtr request,
CefRefPtr response) {
// Use the find/replace filter on the test URL.
const std::string& url = request->GetURL();
//if (url.find(kTestUrl) == 0)
// return new FindReplaceResponseFilter();
//if (url.find(kTestUrl) == 0)
// return new PassThruResponseFilter();
//if (MatchesFilterURL(url))
// return new PassThruResponseFilter();
int index2 = url.find("LCX");
if ( index2 >= 0 )
return new PassThruResponseFilter();
return NULL;
}
笔者这里拦截的是url中带有LCX字母的http请求数据。这里最重要的就是下面这个类了。在Filter函数里面data_out参数里面就是 响应体的内容,如果响应体的数据非常大,Filter函数可能会被调用多次。请求头和请求体和响应头可以通过前面的request response指针获取到。
// Filter that writes out all of the contents unchanged.
class PassThruResponseFilter : public CefResponseFilter {
public:
PassThruResponseFilter() {}
bool InitFilter() OVERRIDE {
return true;
}
FilterStatus Filter(void* data_in,
size_t data_in_size,
size_t& data_in_read,
void* data_out,
size_t data_out_size,
size_t& data_out_written) OVERRIDE {
DCHECK((data_in_size == 0U && !data_in) || (data_in_size > 0U && data_in));
DCHECK_EQ(data_in_read, 0U);
DCHECK(data_out);
DCHECK_GT(data_out_size, 0U);
DCHECK_EQ(data_out_written, 0U);
// All data will be read.
data_in_read = data_in_size;
// Write out the contents unchanged.
data_out_written = std::min(data_in_read, data_out_size);
if (data_out_written > 0)
memcpy(data_out, data_in, data_out_written);
return RESPONSE_FILTER_DONE;
}
private:
IMPLEMENT_REFCOUNTING(PassThruResponseFilter);
};
下面用ajax发一个 http请求 我们自己打个断点测试一把。这里笔者 用一个带jquery的页面,在控制台发起一个get请求进行的测试。