当前位置:   article > 正文

java httpresponse headres属性,http响应头首部Content-Length

java接口响应全局加上一个content-length

本文讲述4个问题

gzip编码与Content-Length的关系

分块编码与Content-Length的关系

file文件已经在服务端进行gzip压缩,那为何在node中用request请求这张图片时(请求的方法为head/get)返回头首部Content-Length还是未压缩前的图片大小?

响应头一定会包含Content-Length首部吗?

在图片性能监控脚本中对站内某页面的所有图片进行请求(采用request模块),以获取图片的具体大小。(通过response.headers的Content-Length)

// 部分代码

request.head('http://file.showjoy.com/images/46/4695c19423cd40469fb89836373c1d45.jpg', function (error, response, body) {

console.log(response.headers['content-cength'])

// 'content-length': '812401'

})

对超过阈值的图片会邮件进行提醒:

eb20b79a264291ae5b4f902834e30d5d.png

但是在页面中用chrome查看这张图片时,却发现size只有227kb。

565973aa335a70bb4fc5c0f56def34a3.png

由于file开头的资源是文件服务器上的资源,将file改成cdn1再做尝试。可见图片尺寸大小还是812kb。

d33119e9e37fced7df0a11cd85a8e889.png

cdn1上的资源是由文件服务器上的资源同步上去的,这也意味着相同的资源size不同。造成这样的问题很有可能是服务器对资源做了压缩处理。

cdn http响应头

Accept-Ranges:bytes

Access-Control-Allow-Origin:*

Access-Control-Expose-Headers:X-Log, X-Reqid

Access-Control-Max-Age:2592000

Cache-Control:public, max-age=86400

Connection:keep-alive

Content-Disposition:inline; filename="4695c19423cd40469fb89836373c1d45.jpg"

Content-Length:812401

Content-Transfer-Encoding:binary

Content-Type:image/jpeg

Date:Thu, 04 Aug 2016 10:24:19 GMT

ETag:"FqxG8os4S6llXHllO2ublrIKagfY"

Last-Modified:Mon, 11 Apr 2016 09:05:23 GMT

Server:nginx

X-Log:mc.g;IO:1

X-Qiniu-Zone:0

X-Reqid:6VUAAKhrk3UAkmcU

X-Via:1.1 zhenjiang173:4 (Cdn Cache Server V2.0), 1.1 yzh229:1 (Cdn Cache Server V2.0)

file文件服务器 http响应头

HTTP/1.1 200 OK

Server: Tengine

Date: Thu, 04 Aug 2016 10:23:45 GMT

Content-Type: image/jpeg

Last-Modified: Mon, 11 Apr 2016 09:01:56 GMT

Transfer-Encoding: chunked

Connection: keep-alive

Vary: Accept-Encoding

Expires: Thu, 31 Dec 2037 23:55:55 GMT

Cache-Control: max-age=315360000

Content-Encoding: gzip

可以看出文件服务器开启了Content-Encoding: gzip

内容编码gzip介绍

Accept-Encoding和Content-Encoding是HTTP中用来对「采用何种编码格式传输正文」进行协定的一对头部字段。

工作原理:

浏览器发送请求时,通过Accept-Encoding带上自己支持的内容编码格式列表,服务端从中挑选一种用来对内容编码,编好码的数据就放在实体主体中,再通过Content-Encoding响应头指明选定的格式,浏览器拿到相应正文后再依据Content-Encoding进行解压。

具体过程:

网站服务器生成原始响应报文,其中有原始的Content-Type和Content-Length首部。

内容编码服务器创建编码后的报文,编码后的报文有同样的Content-Type和不同的Content-Length,同时增加了Content-Encoding首部。

接收程序得到编码后的报文,进行解码,获得原始报文。

这就有了一系列问题:

file文件已经在服务端进行gzip压缩,那为何在node中用request请求这张图片时(请求的方法为head)返回头首部Content-Length还是未压缩前的图片大小?

响应头一定会包含Content-Length首部吗?

HTTP/1.1 200 OK

Server: Tengine

Date: Fri, 05 Aug 2016 08:08:05 GMT

Connection: keep-alive

Vary: Accept-Encoding

Transfer-Encoding: chunked

Content-Type: image/jpeg

Cache-Control: max-age=315360000

Content-Encoding: gzip

Expires: 0

Cache-Control: no-cache

内容...

HTTP实体首部描述了HTTP报文的内容。在这里可以将实体首部和实体主体想象结合成一个箱子,实体首部是箱子上部的描述信息,实体主体则是箱子内货真价实的物品。

响应头的实体首部列表:

Content-Type

Content-Length

Content-Language

Content-Encoding

Content-Location

Content-Range

Content-MD5

Last-Modified

Expires

Allow

ETag

Cache-Control

http的head方法与get方法返回的首行和首部完全相同,不同的是get方法的响应头中会有主体,而head方法在响应中只返回首部,不会返回主体部分,这就允许客户端在未获取实际资源的情况下,对资源的首部进行检查。

所以在编写爬虫的时候使用了request.head方法,快捷地获取所需要的Content-Length。但是为何获取的Content-Length是gzip压缩前的大小呢?

Content-Length 实体的大小

Content-Length首部指示出报文实体主体的字节大小,这个大小是包含了所有内容编码的。比如对文本文件进行了gzip压缩的话,Content-Length首部就是压缩后的大小,而不是原始大小。

另外Content-Length首部对于长连接是必不可少的,长连接代表在连接期间会有多个http请求响应在排队,而服务器不能够关闭连接,客户端只能通过Content-Length知道一条报文在哪里结束,下一条报文在哪里开始。

除非使用了分块编码Transfer-Encoding: chunked,否则响应头首部必须使用Content-Length首部。 [摘自http权威指南]

传输编码和分块编码

分块编码把「报文」分割成若干个大小已知的块,块之间是紧挨着发送的,这样就不需要在发送之前知道整个报文的大小了。(也意味着不需要写回Content-Length首部了)

当使用持久连接时,在服务器写主体之前,必须知道它的大小并在Content-Length首部中发送。如果服务器动态创建内容,可能在发送之前无法知道主体大小,分块编码就是为了解决这种情况。服务器把主体逐块发送,说明每一块的大小。服务器再用大小为0的块作为结束块。,为下一个响应做准备。

再回过头看请求file文件服务器的图片时响应头的首部信息发现了这个首部:Transfer-Encoding: chunked

这也说明了这个图片请求的响应是采用分块编码的传输方式,采用这种传输方式进行响应时,没必要带上Content-Length这个首部信息。因为即使带上了也是不准确的。再回过头看上述file图片的响应头中确实没有Content-Length首部。

但是在node中请求http://file.showjoy.com/images/46/4695c19423cd40469fb89836373c1d45.jpg这张图片,是能取得Content-Length的,这是什么原因?

request.head('http://file.showjoy.com/images/46/4695c19423cd40469fb89836373c1d45.jpg', function (error, response, body) {

console.log(response.headers)

})

===>

{ server: 'Tengine',

date: 'Sun, 07 Aug 2016 04:13:08 GMT',

'content-type': 'image/jpeg',

'content-length': '812401',

'last-modified': 'Mon, 11 Apr 2016 09:01:56 GMT',

connection: 'close',

vary: 'Accept-Encoding',

etag: '"570b6804-c6571"',

expires: 'Thu, 31 Dec 2037 23:55:55 GMT',

'cache-control': 'max-age=315360000',

'accept-ranges': 'bytes' }

上述原因在于在node中请求需要加上Accept-Encoding': 'gzip'首部信息,让服务器知道这个请求支持gzip压缩。不加这个首部,服务器就不会采取gzip压缩,同时我司服务器设定也不进行分块编码。所以返回响应头的Content-Length首部是必须的,但是这个值的大小肯定是没有进行过压缩的。

request(

{ method: 'get'

, uri: 'http://file.showjoy.com/images/46/4695c19423cd40469fb89836373c1d45.jpg'

, gzip: true

}

, function (error, response, body) {

// body is the decompressed response body

console.log(response.headers)

}

)

===>

{ server: 'Tengine',

date: 'Sun, 07 Aug 2016 04:16:10 GMT',

'content-type': 'image/jpeg',

'last-modified': 'Mon, 11 Apr 2016 09:01:56 GMT',

'transfer-encoding': 'chunked',

connection: 'close',

vary: 'Accept-Encoding',

expires: 'Thu, 31 Dec 2037 23:55:55 GMT',

'cache-control': 'max-age=315360000',

'content-encoding': 'gzip' }

同理上面请求示例开启了gzip,文件服务器根据这个标识同时开启了分块编码,致使Content-Length没有返回。

那么如何获取开启了分块编码的响应的文件大小呢?以下是node http原生写法,供大家参考。

var options = {

hostname: 'file.showjoy.com',

port: 80,

path: '/images/7a/7add9f81cd9b41a6aba6271c69719f71.jpg',

method: 'GET',

headers: {

'Accept-Encoding': 'gzip'

}

};

var req = http.request(options, function(res) {

console.log('STATUS: ' + res.statusCode);

console.log('HEADERS: ' + JSON.stringify(res.headers));

var chunks = [];

res.on('data', function (chunk) {

chunks.push(chunk);

})

res.on('end', function () {

console.log('SIZE: ' + chunks.toString().length) // file size

})

})

req.write('data\n');

req.end();

原创文章 欢迎转载。

参考:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/130284
推荐阅读
相关标签
  

闽ICP备14008679号