转载

记一次代码探查过程 - 张涛

摘要

本文原创,转载请注明地址: http://kymjs.com/code/2016/02/25/01

从 Volley 源码中延伸学习到的 HTTP 请求头的知识

  • 事情缘起
  • 曲折的故事
  • 连蒙带猜
  • 原来如此

事情缘起

之所以有这个笔记,是因为这条 Issue: RxVolley #6

在浏览 Volley 代码的时候,产生了一个疑惑

HttpHeaderParser 中有这么一段代码

//...  headerValue = headers.get("Cache-Control"); if (headerValue != null) {     hasCacheControl = true;     String[] tokens = headerValue.split(",");     for (int i = 0; i < tokens.length; i++) {         String token = tokens[i].trim();         if (token.equals("no-cache") || token.equals("no-store")) {             return null;         } else if (token.startsWith("max-age=")) {             try {                 maxAge = Long.parseLong(token.substring(8));             } catch (Exception e) {             }         } else if (token.startsWith("stale-while-revalidate=")) {             try {                 staleWhileRevalidate = Long.parseLong(token.substring(23));             } catch (Exception e) {             }         } else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) {             mustRevalidate = true;         }     } }  //...

这段代码主要用途是在 http 请求响应后,服务器返回的响应数据中如果响应头中声明了 Cache-Control 则按照服务器端的规则处理缓存数据。

问题在于,这里使用的是 headers.get("Cache-Control") 其中 headers 是一个 Map ,那么如果服务器返回的响应头的 key 是一段小写的字符串 cache-control ,那么用这个方法岂不是无法正常读取到 value 了?

曲折的故事

可是,接口返回的数据头中是使用小写的 cache-control 。 使用 Volley 请求这个接口,却发现 HttpHeaderParser 正常工作,并没有出现我们想象中的 headers.get("Cache-Control") 找不到对应 value 的情况。

查看代码, HttpHeaderParser 的参数 headers 是在 Request#parseNetworkResponse() 中被传入的。

而进一步查看是在 NetworkDispatcher 中调用了 parseNetworkResponse() ,代码如下

// Perform the network request. NetworkResponse networkResponse = mNetwork.performRequest(request); request.addMarker("network-http-complete");  // If the server returned 304 AND we delivered a response already, // we're done -- don't deliver a second identical response. if (networkResponse.notModified && request.hasHadResponseDelivered()) {     request.finish("not-modified");     continue; }  // Parse the response here on the worker thread. Response<?> response = request.parseNetworkResponse(networkResponse);

原来这个值是由 mNetwork.performRequest(request) 返回的

再找到 BasicNetwork#performRequest() ,似乎并没有做什么特殊处理啊,为什么这段代码能正常工作呢?

连蒙带猜

难道本身拿到的数据就是大写的 Cache-Control ?

赶紧用 Postman 看一看

记一次代码探查过程 - 张涛

果然是我想多了

记一次代码探查过程 - 张涛

不行,我就是要试试,找到最初发起网络请求的 HurlStack 类,把网络请求返回的请求头数据都给打印出来

// Initialize HttpResponse with data from the HttpURLConnection. ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1); int responseCode = connection.getResponseCode(); if (responseCode == -1) {     // -1 is returned by getResponseCode() if the response code could not be retrieved.     // Signal to the caller that something was wrong with the connection.     throw new IOException("Could not retrieve response code from HttpUrlConnection."); } StatusLine responseStatus = new BasicStatusLine(protocolVersion,         connection.getResponseCode(), connection.getResponseMessage()); BasicHttpResponse response = new BasicHttpResponse(responseStatus); if (hasResponseBody(request.getMethod(), responseStatus.getStatusCode())) {     response.setEntity(entityFromConnection(connection)); } for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {     if (header.getKey() != null) {         Header h = new BasicHeader(header.getKey(), header.getValue().get(0));         Log.i("kymjs", header.getKey()+"===="+header.getValue().get(0))         response.addHeader(h);     } } return response;

记一次代码探查过程 - 张涛

记一次代码探查过程 - 张涛

我操,为什么又变成了大写的。

原来如此

连蒙带猜的,服务器接口返回的是小写,数据请求拿到的是大小,这特么说明在网络过程中数据发生了变化啊。

赶紧去查查 Http 1.1 协议: https://tools.ietf.org/html/rfc7230

https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html

3.2 Header Fields

Each header field consists of a case-insensitive field name followed by a colon (“:”), optional leading whitespace, the field value, and optional trailing whitespace.

4.2 Message Headers

HTTP header fields, which include general-header (section 4.5), request-header (section 5.3), response-header (section 6.2), and entity-header (section 7.1) fields, follow the same generic format as that given in Section 3.1 of RFC 822 [9]. Each header field consists of a name followed by a colon (“:”) and the field value. Field names are case-insensitive.

大意就是说:HTTP头字段遵循相同的通用格式,字段名称是不区分大小写的。

原来如此,那么通用格式肯定就是指 Cache-Control 这种首字母大写的格式了。

wiki百科查一下,是这样。 HTTP头字段列表 回应字段: https://zh.wikipedia.org/wiki/HTTP%E5%A4%B4%E5%AD%97%E6%AE%B5%E5%88%97%E8%A1%A8

了却了心中的一个疑问,真舒服~

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

原文  http://www.kymjs.com/code/2016/02/25/01/
正文到此结束
Loading...