OkHttp的性能指标拦截(首包,剩余包时间,resultCode)
2016-03-17 11:58
549 查看
最近,部门接到新的任务就是做httpClient,URLConnection,OKhttpClient,webview的网络性能指标进行监控,当然这些指标最准确的方法还是使用jni在底层建链与dns解析,发包等函数进行hook,再进行指标采集。但领导要求我们在java层尝试一下,今天主要记录下,我对OkHttp网络指标采集的调研结果和尝试。
对于httpClient我们通尝都是替换execute()方法,然后对httpClient的对像进行更改配置自己的拦截功能,查看源码,发现OkHttpClient相对不同的是execute方法并不在OkHttpClient,而是newCall方法中new 了一个call实例。
发现Call类并不是final的,所以决定对其继承,因为 Call的构造器是protected的,所以子类需要在相同的包名下,而上层的拦截于是这样实现的
MyCall类的中的public,protected方法进行重写(execute(),enqueue(Callback paramCallback),cancel(),isCanceled()),实现使用传入的call进行调用,重写getResponse方法
算出首包,剩余包时间和拦截重定向,通过重写enqueue方法,获取清求的错误与response
OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(url).get().build(); Response response = client.newCall(request).execute();
对于httpClient我们通尝都是替换execute()方法,然后对httpClient的对像进行更改配置自己的拦截功能,查看源码,发现OkHttpClient相对不同的是execute方法并不在OkHttpClient,而是newCall方法中new 了一个call实例。
public Call newCall(Request request) { return new Call(this, request); } //Call构造器中,对OkHttpClient进行了深拷备,所以对newCall之后的OkHttpClient配置都将无法生效,所以我们必须在newCall之前将拦截代码进行塞入 Call(OkHttpClient client, Request originalRequest) { // Copy the client. Otherwise changes (socket factory, redirect policy, // etc.) may incorrectly be reflected in the request when it is // executed. this.client = client.copyWithDefaults(); this.originalRequest = originalRequest; }
发现Call类并不是final的,所以决定对其继承,因为 Call的构造器是protected的,所以子类需要在相同的包名下,而上层的拦截于是这样实现的
public static Call newCall(OkHttpClient okHttpClient, Request paramRequest) { return new MyCall(okHttpClient, paramRequest, okHttpClient.newCall(paramRequest)); }
MyCall类的中的public,protected方法进行重写(execute(),enqueue(Callback paramCallback),cancel(),isCanceled()),实现使用传入的call进行调用,重写getResponse方法
@Override Response getResponse(Request request, boolean forWebSocket) throws IOException { RequestBody body = request.body(); if (body != null) { Request.Builder requestBuilder = request.newBuilder(); MediaType contentType = body.contentType(); if (contentType != null) { requestBuilder.header("Content-Type", contentType.toString()); } long contentLength = body.contentLength(); if (contentLength != -1) { requestBuilder.header("Content-Length", Long.toString(contentLength)); requestBuilder.removeHeader("Transfer-Encoding"); } else { requestBuilder.header("Transfer-Encoding", "chunked"); requestBuilder.removeHeader("Content-Length"); } request = requestBuilder.build(); } // Create the initial HTTP engine. Retries and redirects need new engine // for each attempt. engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null, null); int followUpCount = 0; while (true) { if (canceled) { engine.releaseConnection(); throw new IOException("Canceled"); } try { Timer requestTime = ThreadLocalMetricsRecorder.getInstance().getRequestTimer(); Timer responseTime = ThreadLocalMetricsRecorder.getInstance().getResponseTimer(); requestTime.start(); engine.sendRequest(); requestTime.stop(); responseTime.start(); engine.readResponse(); responseTime.stop(); } catch (RequestException e) { // The attempt to interpret the request failed. Give up. throw e.getCause(); } catch (RouteException e) { // The attempt to connect via a route failed. The request will // not have been sent. HttpEngine retryEngine = engine.recover(e); if (retryEngine != null) { engine = retryEngine; continue; } // Give up; recovery is not possible. throw e.getLastConnectException(); } catch (IOException e) { // An attempt to communicate with a server failed. The request // may have been sent. HttpEngine retryEngine = engine.recover(e, null); if (retryEngine != null) { engine = retryEngine; continue; } // Give up; recovery is not possible. throw e; } Response response = engine.getResponse(); Request followUp = engine.followUpRequest(); if (followUp == null) { if (!forWebSocket) { engine.releaseConnection(); } return response; } if (++followUpCount > MAX_FOLLOW_UPS) { throw new ProtocolException("Too many follow-up requests: " + followUpCount); } if (!engine.sameConnection(followUp.url())) { engine.releaseConnection(); } Connection connection = engine.close(); request = followUp; engine = new HttpEngine(client, request, false, false, forWebSocket, connection, null, null, response); } }
算出首包,剩余包时间和拦截重定向,通过重写enqueue方法,获取清求的错误与response
@Override public void enqueue(Callback paramCallback) { // a(); this.e.enqueue(new Callback() { @Override public void onResponse(Response response) throws IOException { } @Override public void onFailure(Request request, IOException e) { } }); }
相关文章推荐
- 女网络工程师工作学习交流群,群号码:296239702
- iOS系统网络抓包方法
- 完美解决failed to open stream: HTTP request failed!(file_get_contents引起的)
- 文件分包网络传输Demo
- TCP/IP四层模型和OSI七层模型的概念
- iOS通过http post上传图片
- python网络学习(05)
- Https传输中加密和密钥交换涉及到的算法总结与介绍
- xcode7.2 App Transport Security has blocked a cleartext HTTP 报错解决办法
- http 中文问题
- 用Okhttp框架登录之后的Cookie设置到webView中
- HttpServletResponse addHeader() 与 setHeader() 区别
- android 从网络加载图片并显示
- HTTPS的七个误解
- python网络学习(04)
- HTTPS单向认证和双向认证
- python网络学习(03)
- tomcat------https单向认证和双向认证
- python网络学习(02)
- 静态路由命令配置