HAR(HTTP档案规范),是一个用来储存HTTP请求/响应信息的通用文件格式,基于JSON。这种格式的数据可以使HTTP监测工具以一种通用的格式导出所收集的数据,这些数据可以被其他支持HAR的HTTP分析工具(包括Firebug、httpwatch、Fiddler等)所使用,来分析网站的性能瓶颈。
http://horve.github.io/2015/09/08/har-detail/
|
|
在resources目录下加入log4j.properties
log4j.rootLogger = INFO, stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d %p [%c] - %m%n
注:
一定要配置好日志环境,否则系统出错了完全看不出来。血泪教训。
在我配置时候,BMP2.1.4 和 Guava22.0 是不兼容的,导致服务起来之后,浏览器始终无法打开页面。然而,没有任何迹象表现出代理没有起来,或者运行过程中有错。
多方Google无果,因为完全没有日志记录。只能搜索 “browsermob not working” 或者 “browsermob connection reset”等等毫无意义的现象。然而什么都没有搜出来。
最后,配好了日志环境,发现了错误。
java.lang.NoSuchMethodError:com.google.common.net.HostAndPort.getHostText()
经过搜索发现,实际上是由于BMP官方兼容性问题导致。
https://github.com/lightbody/browsermob-proxy/issues/638
|
BrowserMobProxy proxy =
new BrowserMobProxyServer();
proxy.start(
8180, InetAddress.getByName("localhost")
);
// 不要用常见的 8888 被 Charles用啦
Thread.sleep(10000000);
proxy.stop();
|
这样就算起了好了一个代理服务器,端口是8888。
是不是非常简单。
代理启动之后,主线程可以Sleep一段时间,然后把代理关掉,这样就能够实现定时关闭代理的功能了。
实际上,还可以拦截请求,在某些请求完成之后关闭代理。
由于代理是单独线程,跟启动它的主线程没有关系,因此主线程Sleep不会影响代理的可用性。
|
BrowserMobProxy proxy = new BrowserMobProxyServer();
proxy.start(8100, InetAddress.getByName("localhost"));
// 不要用常见的 8888 被 Charles用啦
|
RequestFilter
proxy.addRequestFilter((request, contents, messageInfo) -> {
if (request.getMethod().equals(HttpMethod.POST)) {
System.out.println(request.getUri() + " ######### " + contents.getTextContents());
}
System.out.println(request.getUri() + " --->> " + request.headers().get("Cookie"));
return null;
});
RequestFilter 是一个接口,只有一个方法
HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo);
当这个方法在Proxy中被调用的时候,request参数包括了HTTP method, URI, headers等等。这些都是可以修改的。
当POST方法等提请求带有参数的时候,content中可以取到参数详情。content可以通过
HttpMessageContents#setTextContents(String) 或者 HttpMessageContents#setBinaryContents(byte[]) 来进行修改。
对于 request 和 contents 都会直接反映在最终给服务器的请求上。
如果返回值不是null, 那么代理不再往外发送请求,而是直接将这个非空的元素返回去给浏览器。
|
ResponseFilter
proxy.addResponseFilter((response, contents, messageInfo) -> {
System.out.println(
messageInfo.getUrl() + " >>>>>> " + response.getStatus() + " : " +
response.headers().get("cookie") + " | " + contents.getTextContents()
);
});
ResponseFilter是一个接口,只有一个方法 。
void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo);
当这个方法在Proxy中被调用的时候,response参数包括了URI, headers, status line等等。
contents是返回的真正内容,可以通过以下方法来进行修改。
HttpMessageContents#setTextContents(String) 或者 HttpMessageContents#setBinaryContents(byte[])
对response和content的修改,都会最终反映到请求发起方。
|
存储HAR文件
// create a new HAR with label
proxy.newHar("bmp”);
// enable more detailed HAR capture, if desired (see CaptureType for the complete list)
proxy.enableHarCaptureTypes(
CaptureType.
REQUEST_HEADERS, CaptureType.
REQUEST_CONTENT, CaptureType.
REQUEST_BINARY_CONTENT, CaptureType.
REQUEST_COOKIES, CaptureType.
RESPONSE_HEADERS, CaptureType.
RESPONSE_CONTENT, CaptureType.
RESPONSE_BINARY_CONTENT, CaptureType.
RESPONSE_COOKIES);
// 手动输入验证码,然后继续爬取过程
while (true) {
Scanner scanner = new Scanner(System.in);
String cmd = scanner.next();
if(cmd.equals("quit")){
break;
}
}
try {
Har har = proxy.getHar();
File harFile = new File("/Users/wangqi/Desktop/bmp.har");
har.writeTo(harFile);
} catch (IOException ioe) {
ioe.printStackTrace();
}
proxy.stop();
http://www.swtestacademy.com/webdriver-browsermob-proxy/
在线工具 http://www.softwareishard.com/ 或者 Charles 可以打开存储下来的HAR文件。
由于HAR需要用Charles打开,而Charles默认的代理端口是8888,当Charles开启,所以如果BMP使用8888,可能出现一只拿不到任何HAR的诡异情况。
而,实际上,启动过程中竟然么有报端口被占用,也真是诡异。
|
BMP会自动加上一个RequestHeader,为了减少服务器对代理的影响,需要删除该Header信息。
https://github.com/lightbody/browsermob-proxy/issues/213
proxy.addLastHttpFilterFactory(new HttpFiltersSourceAdapter() {
@Override
public HttpFilters filterRequest(HttpRequest originalRequest) {
return new HttpFiltersAdapter(originalRequest) {
@Override
public HttpResponse proxyToServerRequest(HttpObject httpObject) {
if (httpObject instanceof HttpRequest) {
((HttpRequest) httpObject).headers().remove(HttpHeaders.Names.VIA);
}
return null;
}
};
}
});
|
// start the proxy
BrowserMobProxy proxy = new BrowserMobProxyServer();
proxy.start(0);
// get the Selenium proxy object
Proxy seleniumProxy = ClientUtil.createSeleniumProxy(proxy);
// configure it as a desired capability
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(CapabilityType.PROXY, seleniumProxy);
// start the browser up
WebDriver driver = new FirefoxDriver(capabilities);
// enable more detailed HAR capture, if desired (see CaptureType for the complete list)
proxy.enableHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT);
// create a new HAR with the label "yahoo.com"
proxy.newHar("yahoo.com");
// open yahoo.com
driver.get("http://yahoo.com");
// get the HAR data
Har har = proxy.getHar();
|