http协议-html与http的区别

大白话:html协议是  保存信息的  文档协议,http协议 是 传输信息的 传输协议。

在Web服务中,信息一般是使用HTML格式以超文本和超媒体方式传送的,所使用的Internet协议是HTTP协议。

HTTP  意为超文本传输协议(全称是Hypertext Transfer Protocol)。是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示等(如文本先于图形显示)。这就是我们为什么在浏览器中看到的网址都是以“http://”开头的原因。

HTML  释为超文本标记语言(全称是Hypertext Markup Language),是用于WWW上文档的格式化语言。使用HTML语言可以创建文本文档,该文档可以从一个平台移植到另一个平台。HTML文件是带有嵌入代码(由标记表示)的ASCII文本文件,它用来表示格式化和超文本链接。HTML文件的内容通过一个页面展示出来,不同页面通过超链接关联起来。

 

http协议-headers-各字段详解

Cache-Control:must-revalidate, no-cache, private。

这个值告诉客户端,服务端不希望客户端缓存资源,在下次请求资源时,必须要从新请求服务器,不能从缓存副本中获取资源。
Cache-Control是响应头中很重要的信息,当客户端请求头中包含Cache-Control:max-age=0请求,明确表示不会缓存服务器资源时,Cache-Control作为作为回应信息,通常会返回no-cache,意思就是说,“不缓存就不缓存呗”;当客户端在请求头中没有包含Cache-Control时,服务端往往会定,不同的资源不同的缓存策略,比如说oschina在缓存图片资源的策略就是Cache-Control:max-age=86400,这个意思是,从当前时间开始,在86400秒的时间内,客户端可以直接从缓存副本中读取资源,而不需要向服务器请求。

Connection:keep-alive

这个字段作为回应客户端的Connection:keep-alive,告诉客户端服务器的tcp连接也是一个长连接,客户端可以继续使用这个tcp连接发送http请求。关于长连接的更多知识,后面我再详细讲。

Content-Encoding:gzip

告诉客户端,服务端发送的资源是采用gzip编码的,客户端看到这个信息后,应该采用gzip对资源进行解码。

Content-Type:text/html;charset=UTF-8

告诉客户端,资源文件的类型,还有字符编码,客户端通过utf-8对资源进行解码,然后对资源进行html解析。通常我们会看到有些网站是乱码的,往往就是服务器端没有返回正确的编码。

Content-type: text/html; charset=xxx的优先级要高于
<META http-equiv=”content-type” content=”text/html; charset=xxx”>
因为一个在headers中,一个在网页中。浏览器响应时,有时候是json文件,pdf文件等,这些文件里面没有设置编码,不像网页文件内部可以设置编码。所以headers中的>Content-type 优先级更高。

服务器可以设置响应文件的编码,其实功能相当于在 headers中设置 Content-type。如果headers已经有了Content-type,那就按服务器设置的方案,修改编码方式。

对于网页编码,headers中Content-type: text/html; charset=xxx;可以不用指定charset=xxx;因为网页内部也可以设置编码方案。

当时做了一个简易的web服务器,关键细节总结。

返回消息时,http 请求头和请求体 之间 需要 加 一个  【回车+换行】两个步骤。当然,java里面就一句  xxx.println();

当时,输出响应头时:

xxx.println(“Content-Type: text/css”); 这个css的类型,没有单独写。只是用if else 单独判断输出了   text/html   text/javascript   text/png    image/jpeg   image/gif  ,其他的 一律输出  application/octet-stream  类型。所以一开始,请求 css 文件 时,响应头是  application/octet-stream  类型。然后,浏览器加载网页时,居然没有加载 css 文件。因为它认为 下载 的css文件,类型不对。所以网页渲染时,页面布局 混乱了。后来改成 输出 Content-Type: text/css 时,页面渲染成功了。

ETAG:字符串(出现在http1.1协议中,可选字段)

ETag在HTTP头字段中的使用是可选的(不像HTTP/1.1的其他头字段是强制性的)。HTTP规范从未指定生成ETag的方法。

ETag又叫实体标签(entity tag)是HTTP协议提供的若干机制中的一种Web缓存验证机制,并且允许客户端进行缓存协商。这就使得缓存变得更加高效,而且节省带宽。如果资源的内容没有发生改变,Web服务器就不需要发送一个完整的响应。ETag也可用于乐观并发控制,作为一种防止资源同步更新而相互覆盖的方法。

ETag是一个不透明的标识符,由Web服务器根据URL上的资源的特定版本而指定。如果那个URL上的资源内容改变,一个新的不一样的ETag就会被分配。用这种方法使用ETag即类似于指纹,并且他们能够被快速地被比较,以确定两个版本的资源是否相同。ETag的比较只对同一个URL有意义——不同URL上的资源的ETag值可能相同也可能不同,从他们的ETag的比较中无从推断。

Date:Sun, 21 Sep 2014 06:18:21 GMT

这个是服务端发送资源时的服务器时间,刚开始我不知道GMT是格林尼治所在地的标准时间,以为是服务器的时间错了,还去服务器上查看过时间。http协议中发送的时间都是GMT的,这主要是解决在互联网上,不同时区在相互请求资源的时候,时间混乱问题。

Expires:Sun, 1 Jan 2000 01:00:00 GMT

这个响应头也是跟缓存有关的,告诉客户端在这个时间前,可以直接访问缓存副本,很显然这个值会存在问题,因为客户端和服务器的时间不一定会都是相同的,如果时间不同就会导致问题。所以这个响应头是没有Cache-Control:max-age=***这个响应头准确的,因为max-age=date中的date是个相对时间,不仅更好理解,也更准确。

Pragma:no-cache

这个含义与Cache-Control等同。

Server:Tengine/1.4.6

这个是服务器和相对应的版本,只是告诉客户端服务器信息,没有更多的意思。

Transfer-Encoding:chunked

这个响应头告诉客户端,服务器发送的资源的方式是分块发送的。一般分块发送的资源都是服务器动态生成的,在发送时还不知道发送资源的大小,所以采用分块发送,每一块都是独立的,独立的块都能标示自己的长度,最后一块是0长度的,当客户端读到这个0长度的块时,就可以确定资源已经传输完了。


HTTP Header 之Content-Type介绍

Content-Type 实体头部用于指示资源的MIME类型 media type 。

在响应中,Content-Type标头告诉客户端实际返回的内容的内容类型。浏览器会在某些情况下进行MIME查找,并不一定遵循此标题的值; 为了防止这种行为,可以将标题 X-Content-Type-Options 设置为 nosniff

在请求中 (如POST 或 PUT),客户端告诉服务器实际发送的数据类型。

Header type Entity header
Forbidden header name no
CORS-safelisted response-header yes
句法
Content-Type: text/html; charset=utf-8
Content-Type: multipart/form-data; boundary=something
指令
media-type
资源或数据的 MIME type 。
charset
字符编码标准。
boundary
对于多部分实体,boundary 是必需的,其包括来自一组字符的1到70个字符,已知通过电子邮件网关是非常健壮的,而不是以空白结尾。它用于封装消息的多个部分的边界。
例子

Content-Type 在HTML表单中

在通过HTML form提交生成的POST请求中,请求头的Content-Type由<form>元素上的enctype属性指定

<form action="/" method="post" enctype="multipart/form-data">
  <input type="text" name="description" value="some text">
  <input type="file" name="myFile">
  <button type="submit">Submit</button>
</form>

请求头看起来像这样(在这里省略了一些 headers):

POST /foo HTTP/1.1
Content-Length: 68137
Content-Type: multipart/form-data; boundary=---------------------------974767299852498929531610575

---------------------------974767299852498929531610575
Content-Disposition: form-data; name="description" 

some text
---------------------------974767299852498929531610575
Content-Disposition: form-data; name="myFile"; filename="foo.txt" 
Content-Type: text/plain 

(content of the uploaded file foo.txt)
---------------------------974767299852498929531610575
规范
Specification Title
RFC 7233, section 4.1: Content-Type in multipart Hypertext Transfer Protocol (HTTP/1.1): Range Requests
RFC 7231, section 3.1.1.5: Content-Type Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content

 

参考:

https://my.oschina.net/manmao/blog/549123

http协议-浏览器和服务器协商http协议版本的过程探讨

How does a HTTP 1.0 only server respond to a HTTP 1.1 request?

Fairly simple question (I think). If a client sends a message like GET /whatever HTTP/1.1 to a server that only supports HTTP 1.0, how does the server react? What are the rules for header fields added in HTTP 1.1 that a HTTP 1.0 server doesn’t recognise? Does the server simply ignore 1.1 requests, ignore headers it doesn’t understand, return an error, or something else?

answer:

HTTP/1.0 200 OK

All headers of HTTP/1.1 (that a HTTP 1.0 server doesn’t recognise) will be ignored.

总之:http 目前支持协议 协商的只有 http1.1 ,浏览器通过 https 协商过程 或者直接用 upgrade 请求头  与服务器 进行协议协商。其他情况,客户端 服务端支持的最高http协议如果相同,则以最高http协议通信。服务端比客户端支持的最高http协议低,服务器会直接 忽略不能识别的请求头。

目前的浏览器,都是采用 http1.1 协议  率先进行 通信,然后 看看服务器 能不能支持 协议 升级,通过http2.0 进行通信。

http协议-headers-http1.1中新增的内容协商功能

HTTP协议的内容协商

一、起因

我们在日常的抓包过程中经常可以看到以Accept开头的请求首部,比如:Accept-Language 有一个q值,肯定有人好奇在HTTP规范中为什么要定义这个q值;还有在响应首部有一个名为Vary的首部,这个首部又有什么意义?如图所示:

本文记录我对 Vary 的一些研究,其中就包含这些问题的答案。

二、内容协商(两种方式)

一种是服务端把文档可用版本列表发给客户端让用户选,这可以使用 300 Multiple Choices 状态码来实现。这种方案有不少问题,首先多一次网络往返;其次服务端同一文档的某些版本可能是为拥有某些技术特征的客户端准备的,而普通用户不一定了解这些细节。举个例子,服务端通常可以将静态资源输出为压缩和未压缩两个版本,压缩版显然是为支持压缩的客户端而准备的,但如果让普通用户选,很可能选择错误的版本。

所以 HTTP 的内容协商通常使用另外一种方案:服务端根据客户端发送的请求头中某些字段自动发送最合适的版本。可以用于这个机制的请求头字段又分两种:内容协商专用字段(Accept 字段)、其他字段。

首先来看 Accept 字段,详见下表:

请求头字段 说明 响应头字段
Accept 告知服务器发送何种媒体类型 Content-Type
Accept-Language 告知服务器发送何种语言 Content-Language
Accept-Charset 告知服务器发送何种字符集 Content-Type
Accept-Encoding 告知服务器采用何种压缩方式 Content-Encoding

例如客户端发送以下请求头:

Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:zh-CN,en-US;q=0.8,en;q=0.6

表示它可以接受任何 MIME 类型的资源;支持采用 gzip、deflate 或 sdch 压缩过的资源;可以接受 zh-CN、en-US 和 en 三种语言,并且 zh-CN 的权重最高(q 取值 0 – 1,最高为 1,最低为 0,默认为 1),服务端应该优先返回语言等于 zh-CN 的版本。q值的范围从0.0~1.0(1.0优先级最高)

浏览器的响应头可能是这样的:

Content-Type: text/javascript
Content-Encoding: gzip

表示这个文档确切的 MIME 类型是 text/javascript;文档内容进行了 gzip 压缩;响应头没有 Content-Language 字段,通常说明返回版本的语言正好是请求头 Accept-Language 中权重最高的那个。

三、vary的由来

有时候,上面四个 Accept 字段并不够用,例如要针对特定浏览器如 IE6 输出不一样的内容,就需要用到请求头中的 User-Agent 字段。类似的,请求头中的 Cookie 也可能被服务端用做输出差异化内容的依据。

由于客户端和服务端之间可能存在一个或多个中间实体(如缓存服务器),而缓存服务最基本的要求是给用户返回正确的文档。如果服务端根据不同 User-Agent 返回不同内容,而缓存服务器把 IE6 用户的响应缓存下来,并返回给使用其他浏览器的用户,肯定会出问题 。

所以 HTTP 协议规定,如果服务端提供的内容取决于 User-Agent 这样「常规 Accept 协商字段之外」的请求头字段,那么响应头中必须包含 Vary 字段,且 Vary 的内容必须包含 User-Agent。同理,如果服务端同时使用请求头中 User-Agent 和 Cookie 这两个字段来生成内容,那么响应中的 Vary 字段看上去应该是这样的:

Vary: User-Agent, Cookie

也就是说 Vary 字段用于列出一个响应字段列表,告诉缓存服务器遇到同一个 URL 对应着不同版本文档的情况时,如何缓存和筛选合适的版本。

 

不过查看:RFC 的vary头的例子就是 Vary: accept-encoding, accept-language ,可见accept-*也可以放在vary中。cache的唯一性只取决于request的vary里指定的headers。也就是从RFC 的文本来看,http设计上vary/cache机制和内容协商机制是正交的。

大白话:就是说 缓存机制 看的就是 vary,vary 里面不仅有User-Agent, Cookie字段,也可以有accept-* 字段,用来标记区分缓存。

关于vary 里面的 accept-encoding,比较特殊。第一,(按道理)压缩并不改变真正的内容,所以稍微聪明点的proxy就可以自行处理而不影响cache。第二,新版spec好像要求所有client必须支持gzip。所以accept-encoding有没有就没什么关系了。但是其他accept头就不一样。如果要作为区分缓存的标记,必须在vary中写明。

举例来说:
web服务器添加响应首部Vary: Accept-Encoding 告知代理服务器根据客户端的请求首部Accept-Encoding缓存不同的版本,这样下次客户端请求同一资源时,根据Accept-Encoding选择相应的缓存版本响应。
其实我们还可以禁用中间实体的缓存功能解决该问题:
web服务器设置响应首部: Cache-Control: private
通常添加Vary首部的解决方案比较通用,因为我们还是希望充分利用中间实体的缓存功能的。

四、Nginx 和 SPDY

通常,上面说的这些工作,Web Server 都可以帮我们搞定。对于 Nginx 来说,下面这个配置可以自动给启用了 gzip 的响应加上 Vary: Accept-Encoding:

gzip_vary on;

用 curl 验证我博客的 js 文件,响应头如下:

jerry@www:~$ curl --head https://imququ.com/.../xx.js

HTTP/1.1 200 OK
Server: nginx
Date: Tue, 31 Dec 2013 16:34:48 GMT
Content-Type: application/x-javascript
Content-Length: 66748
Last-Modified: Tue, 31 Dec 2013 14:30:52 GMT
Connection: keep-alive
Vary: Accept-Encoding
ETag: "52c2d51c-104bc"
Expires: Fri, 29 Dec 2023 16:34:48 GMT
Cache-Control: max-age=315360000
Strict-Transport-Security: max-age=31536000
Accept-Ranges: bytes

可以看到,服务端正确输出了「Vary: Accept-Encoding」,一切正常。
但是用 Chrome 自带抓包工具看下,这个响应头却是这样:

HTTP/1.1 200 OK
cache-control: max-age=315360000
content-encoding: gzip
content-type: application/x-javascript
date: Tue, 31 Dec 2013 16:35:27 GMT
expires: Fri, 29 Dec 2023 16:35:27 GMT
last-modified: Tue, 31 Dec 2013 14:30:52 GMT
server: nginx
status: 200
strict-transport-security: max-age=31536000
version: HTTP/1.1

我的博客支持 SPDY/2 协议,用 Chrome 访问我博客会走 SPDY,所以上面的响应头看上有点不同寻常,例如字段名都变成了小写;多了 status、version 等字段,这些变化下次专门介绍(注:见「SPDY 3.1 中的请求 / 响应头」)。神奇的是尽管服务端没任何变化,但响应中的 Vary: Accept-Encoding 却不见了。

SPDY 规定客户端必须支持压缩,这意味着 SPDY 服务器可以直接启用压缩而不用关心请求头中的 Accept-Encoding 字段。下面这段来自 Nginx 支持的 SPDY/2 协议:

User-agents are expected to support gzip and deflate compression. Regardless of the Accept-Encoding sent by the user-agent, the server may select gzip or deflate encoding at any time. [via]

于是,对于支持 SPDY 的客户端来说,Vary: Accept-Encoding 没有用途,Nginx 选择直接去掉它,可以节省一点流量。curl 或其他不支持 SPDY 协议的客户端还是走 HTTP 协议,所以看到的响应头是常规的。

Nginx 的这个做法是否合适一直有争论,实际上并不是所有支持 SPDY 的 Web Server 都会这么做。例如即使通过 SPDY 协议访问 Google 首页的 js 文件,依然可以看到 vary: Accept-Encoding:

HTTP/1.1 200 OK
status: 200 OK
version: HTTP/1.1
age: 25762
alternate-protocol: 443:quic
cache-control: public, max-age=31536000
content-encoding: gzip
content-length: 154614
content-type: text/javascript; charset=UTF-8
date: Tue, 31 Dec 2013 23:23:51 GMT
expires: Wed, 31 Dec 2014 23:23:51 GMT
last-modified: Mon, 16 Dec 2013 21:54:35 GMT
server: sffe
vary: Accept-Encoding
x-content-type-options: nosniff
x-xss-protection: 1; mode=block

PS:Vary 在 IE 下有很多坑,使用时要格外小心。网上这部分文章比较多,例如 hax 早年写的 IE 与 Vary 头,可以点过去了解下。[但是看评价有很多踩得,不知道可信度怎么样,就当个参考思路吧]


参考
书籍:《HTTP权威指南》
屈屈的博文:https://www.imququ.com/post/vary-header-in-http.html

http协议- HTTP/0.9, HTTP/1.0, HTTP/1.1, Keep-Alive, Upgrade, and HTTPS的发展简史

原文:https://medium.com/platform-engineer/evolution-of-http-69cfe6531ba0
译文:

了解http是如何在真实世界工作的

Disclaimer: This article focuses on explaining some underlying implementation details of HTTP, which will be helpful for readers to better understand my blog article — “Web API Design with HTTP and Websockets


在1989 – 1991年由 Tim Berners-Lee 在 CERN(欧洲核子研究组织) 发明的HTTP(超文本传输​​协议)是万维网的底层通信协议。HTTP在客户端 – 服务器计算模型中用作请求 – 响应协议。HTTP标准由互联网工程任务组(IETF)和万维网联盟(W3C)开发,最终发布了一系列征求意见稿(RFC)。HTTP有四个版本 – HTTP / 0.9,HTTP / 1.0,HTTP / 1.1和HTTP / 2.0。今天常用的版本是HTTP / 1.1,未来将是HTTP / 2.0。

HTTP / 0.9 – 单行协议

  • HTTP的初始版本 – 一种简单的客户端服务器,请求响应和远程协议
  • 请求性质:单行(方法+请求文档的路径)
  • 支持的方法:GET仅限
  • 响应类型:仅限超文本
  • 连接性质:响应后立即终止
  • 没有HTTP标头(不能传输其他内容类型文件),没有状态/错误代码,没有URL,没有版本
$> telnet ashenlive.com 80
(Connection 1 Establishment - TCP Three-Way Handshake)
Connected to xxx.xxx.xxx.xxx
(Request)
GET /my-page.html
(Response in hypertext)
<HTML>
A very simple HTML page
</HTML>
(Connection 1 Closed - TCP Teardown)

流行的Web服务器(Apache,Nginx)仍支持HTTP / 0/9。尝试打开Telnet会话并访问google.com

HTTP / 1.0 – 拥有扩展性

  • 浏览器友好的协议
  • 提供的头字段包括有关请求和响应的丰富元数据(HTTP版本号,状态代码,内容类型)
  • 回应:不限于超文本(Content-Type头文件提供传输纯HTML文件以外的文件的能力 – 例如脚本,样式表,媒体)
  • 支持的方法:GET ,HEAD ,POST
  • 连接性质:响应后立即终止
(Connection 1 Establishment - TCP Three-Way Handshake)
Connected to xxx.xxx.xxx.xxx
(Request)
GET /my-page.html HTTP/1.0 
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)
(Response)
HTTP/1.0 200 OK 
Content-Type: text/html 
Content-Length: 137582
Expires: Thu, 01 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 1 May 1996 12:45:26 GMT
Server: Apache 0.84

<HTML> 
A page with an image
  <IMG SRC="/myimage.gif">
</HTML>
(Connection 1 Closed - TCP Teardown)
------------------------------------------
(Connection 2 Establishment - TCP Three-Way Handshake)
Connected to xxx.xxx.xxx.xxx
(Request)
GET /myimage.gif HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)

(Response)
HTTP/1.0 200 OK 
Content-Type: text/gif 
Content-Length: 137582
Expires: Thu, 01 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 1 May 1996 12:45:26 GMT
Server: Apache 0.84
[image content]
(Connection 2 Closed - TCP Teardown)

HTTP / 0.9和HTTP / 1.0中的主要问题-为每个请求建立新连接

HTTP / 0.9和HTTP / 1.0都需要为每个请求打开一个新连接(并在发送响应后立即关闭它)。每次建立新的连接时,TCP三方握手也应该发生。为了获得更好的性能,减少客户端和服务器之间的这些往返行为至关重要。HTTP / 1.1通过持久连接解决了这个问题。


一个典型的TCP三次握手(查看TCP状态机如何改变其状态)来自  lwn.net

HTTP / 1.1 – 标准化协议

  • 这是目前常用的HTTP版本。
  • 引入了关键性能优化和功能增强 – 持久和流水线连接,分块传输,压缩/解压缩,内容协商,虚拟主机(具有多个域的单个IP地址的服务器),通过添加缓存支持更快的响应和更大的带宽节省。
  • 支持的方法:GET ,HEAD ,POST ,PUT ,DELETE ,TRACE ,OPTIONS
  • 连接性:保持连接
(Connection 1 Establishment - TCP Three-Way Handshake)
Connected to xxx.xxx.xxx.xxx
(Request 1)
GET /en-US/docs/Glossary/Simple_header HTTP/1.1
Host: developer.mozilla.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/en-US/docs/Glossary/Simple_header

(Response 1)
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Wed, 20 Jul 2016 10:55:30 GMT
Etag: "547fa7e369ef56031dd3bff2ace9fc0832eb251a"
Keep-Alive: timeout=5, max=1000
Last-Modified: Tue, 19 Jul 2016 00:59:33 GMT
Server: Apache
Transfer-Encoding: chunked
Vary: Cookie, Accept-Encoding

[content]

(Request 2)
GET /static/img/header-background.png HTTP/1.1
Host: developer.cdn.mozilla.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/en-US/docs/Glossary/Simple_header

(Response 2)
HTTP/1.1 200 OK
Age: 9578461
Cache-Control: public, max-age=315360000
Connection: keep-alive
Content-Length: 3077
Content-Type: image/png
Date: Thu, 31 Mar 2016 13:34:46 GMT
Last-Modified: Wed, 21 Oct 2015 18:27:50 GMT
Server: Apache

[image content of 3077 bytes]
(Connection 1 Closed - TCP Teardown)

在建立任何连接之前,会发生TCP三次握手。最后,在将所有数据发送到客户端之后,服务器发送一条消息,表示没有更多数据要发送。然后客户端关闭连接(TCP拆卸)。HTTP / 1.0中的问题是,对于每个请求 – 响应周期,都需要打开和关闭连接。而使用HTTP / 1.1的优点是,我们可以重复使用相同的开放连接来处理多个请求 – 响应周期。(图片来自informit.com

Keep-Alive和Upgrade 头字段

Keep-Alive 报头

  • Keep-Alive报头在HTTP/ 1.1之前就已经使用(需要显示指明),到了HTTP / 1.1时Keep-Alive成为默认行为。Keep-Alive头可用于定义主机之间长期通信的策略(即允许连接保持活动状态直到发生事件)。为现代Web通信协议中的持久性,可重用连接,流水线和更多增强功能奠定了基础。
  • 客户端,服务器或任何中介都可以为Keep-Alive 添加额外信息。此外,主机可以添加timeoutmax以设置一个超时或每个连接限制最大请求数参数。
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Thu, 11 Aug 2016 15:23:13 GMT
Keep-Alive: timeout=5, max=1000
Last-Modified: Mon, 25 Jul 2016 04:32:39 GMT
Server: Apache

[body]

来自ietf.org的例子展示了如何使用Keep-Alive头文件。所有连接都是独立协商的。客户端指示600秒(10分钟)的超时,但代理仅准备保持连接至少120秒(2分钟)。在代理和服务器之间的链接上,代理请求超时1200秒,服务器将其减少到300秒。如本例所示,代理维护的超时策略对于每个连接都不相同。每个连接跳是独立的

  • 凭借Keep-Alive行为,HTTP流水线,多连接复用以及更多的改进才能实现。

HTTP流水线和多个并行连接(图片来自informit.com

Upgrade 头字段

  • 使用UpgradeHTTP / 1.1中引入的头文件,可以使用常用协议(如HTTP / 1.1)启动连接,然后请求连接切换到增强协议类型(如HTTP / 2.0或WebSockets)。
  • 在升级的协议连接中,max不存在参数(最大请求计数)。升级后的协议可以为timeout参数提供新的策略(如果没有明确定义,它使用底层协议中的默认超时值)。
这个来自ietf.org的例子显示了从HTTP / 1.1到WebSocket [RFC6455] 的升级中包含的头文件。通过websocket升级,每跳中的连接不能在中介的任何一边都有独立的生命周期。升级后,超时策略不能独立于每个连接。代理调整超时值以反映客户端和代理策略设置的值中较低的值,以便服务器知道连接特征; 同样,来自服务器的值被提供给客户端。这个叫逐跳首部 。

第6章 HTTP头部
  • End-to-end 端到端头部
    此类头部字段会转发给 请求/响应 的最终接收目标。
    必须保存在由缓存生成的响应头部。
    必须被转发。
  • Hop-by-hop 逐跳首部
    此类头部字段只对单次转发有效。会因为转发给缓存/代理服务器而失效。
    HTTP 1.1 版本之后,如果要使用Hop-by-hop头部字段则需要提供Connection字段。
    除了一下8个字段为逐跳字段,其余均为端到端字段。

    • Connection
    • Keep-Alive
    • Proxy-Authenticate
    • Proxy-Authenrization
    • Trailer
    • TE
    • Tranfer-Encoding
    • Upgrade

来自 https://blog.csdn.net/u010369338/article/details/69397307

HTTPS

  • 超文本传输​​协议安全(HTTPS)是HTTP的安全版本。它使用SSL / TLS进行安全加密通信。
  • SSL(安全套接字层)最初由Netscape在20世纪90年代中期开发,是对HTTP的加密协议增强,它定义了客户端和服务器应如何安全地相互通信。TLS(传输层安全)是SSL的后继者。
  • 通过为客户端和服务器之间的通信提供双向加密,HTTPS连接可以保护数据传输免受中间人攻击和常见安全威胁的侵害。

来自msdn.microsoft.com上 SSL握手的图解表示 - TCP连接> SSL / TLS客户端Hello> SSL / TLS服务器Hello> SSL / TLS证书> SSL / TLS客户端密钥交换> SSL / TLS新会话票证> HTTPS加密数据交换

 HTTPS中的主要问题 – SSL / TLS握手

  • 虽然HTTPS的设计是安全的,但SSL / TLS握手过程在建立HTTPS连接之前会消耗大量时间。它通常需要1-2秒,并且会大大降低网站的启动性能。

HTTP / 2.0和未来

如今,主要的Web服务器和浏览器都在使用上述所有功能。但是像HTTP / 2.0,服务器端事件(SSE)和Websockets等现代增强功能改变了传统HTTP的工作方式。在我的下一篇关于使用HTTP和Websockets的Web API设计的文章中,我们将讨论如何在实际项目中选择它们。

References:

  1. Evolution of HTTP — MDN Web Docs
  2. Hypertext Transfer Protocol (HTTP) Keep-Alive Header — ietf.org
  3. Protocol upgrade mechanism — MDN Web Docs
  4. Brief History of HTTP — High Performance Browser Networking (hpbn.co)

http协议-http2.0原理详细分析

HTTP 2.0是在SPDY(An experimental protocol for a faster web, The Chromium Projects)基础上形成的下一代互联网通信协议。HTTP/2 的目的是通过支持请求与响应的多路复用来较少延迟,通过压缩HTTPS首部字段将协议开销降低,同时增加请求优先级和服务器端推送的支持。
本文目的是学习HTTP 2.0的原理并研究其通信的详细细节。大部分知识点源于《Web性能权威指南》。

1. 二进制分帧层

二进制分帧层,是HTTP 2.0性能增强的核心。
HTTP 1.x在应用层以纯文本的形式进行通信,而HTTP 2.0将所有的传输信息分割为更小的消息和帧,并对它们采用二进制格式编码。这样,客户端和服务端都需要引入新的二进制编码和解码的机制。
如下图所示,HTTP 2.0并没有改变HTTP 1.x的语义,只是在应用层使用二进制分帧方式传输。

因此,也引入了新的通信单位:

1.1 帧(frame)

HTTP 2.0通信的最小单位,包括帧首部、流标识符、优先值和帧净荷等。

其中,帧类型又可以分为:

  • DATA:用于传输HTTP消息体;
  • HEADERS:用于传输首部字段;
  • SETTINGS:用于约定客户端和服务端的配置数据。比如设置初识的双向流量控制窗口大小;
  • WINDOW_UPDATE:用于调整个别流或个别连接的流量
  • PRIORITY: 用于指定或重新指定引用资源的优先级。
  • RST_STREAM: 用于通知流的非正常终止。
  • PUSH_ PROMISE: 服务端推送许可。
  • PING: 用于计算往返时间,执行“ 活性” 检活。
  • GOAWAY: 用于通知对端停止在当前连接中创建流。

标志位用于不同的帧类型定义特定的消息标志。比如DATA帧就可以使用End Stream: true表示该条消息通信完毕。流标识位表示帧所属的流ID。优先值用于HEADERS帧,表示请求优先级。R表示保留位。
下面是Wireshark抓包的一个DATA帧:

1.2 消息(message)

消息是指逻辑上的HTTP消息(请求/响应)。一系列数据帧组成了一个完整的消息。比如一系列DATA帧和一个HEADERS帧组成了请求消息。

1.3 流(stream)

流是连接中的一个虚拟信道,可以承载双向消息传输。每个流有唯一整数标识符。为了防止两端流ID冲突,客户端发起的流具有奇数ID,服务器端发起的流具有偶数ID。
所有HTTP 2. 0 通信都在一个TCP连接上完成, 这个连接可以承载任意数量的双向数据流Stream。 相应地, 每个数据流以 消息的形式发送, 而消息由一 或多个帧组成, 这些帧可以乱序发送, 然后根据每个帧首部的流标识符重新组装。

二进制分帧层保留了HTTP的语义不受影响,包括首部、方法等,在应用层来看,和HTTP 1.x没有差别。同时,所有同主机的通信能够在一个TCP连接上完成。

2. 多路复用共享连接

基于二进制分帧层,HTTP 2.0可以在共享TCP连接的基础上,同时发送请求和响应。HTTP消息被分解为独立的帧,而不破坏消息本身的语义,交错发送出去,最后在另一端根据流ID和首部将它们重新组合起来。
我们来对比下HTTP 1.x和HTTP 2.0,假设不考虑1.x的pipeline机制,双方四层都是一个TCP连接。客户端向服务度发起三个图片请求/image1.jpg,/image2.jpg,/image3.jpg。
HTTP 1.x发起请求是串行的,image1返回后才能再发起image2,image2返回后才能再发起image3。

HTTP 2.0建立一条TCP连接后,并行传输着3个数据流,客户端向服务端乱序发送stream1~3的一系列的DATA帧,与此同时,服务端已经在返回stream 1的DATA帧

性能对比,高下立见。HTTP 2.0成功解决了HTTP 1.x的队首阻塞问题(TCP层的阻塞仍无法解决),同时,也不需要通过pipeline机制多条TCP连接来实现并行请求与响应。减少了TCP连接数对服务器性能也有很大的提升。

3. 请求优先级

流可以带有一个31bit的优先级:

  • 0:表示最高优先级
  • 231-1:表示最低优先级

客户端明确指定优先级,服务端可以根据这个优先级作为依据交互数据,比如客户端优先级设置为.css>.js>.jpg(具体可参见《高性能网站建设指南》), 服务端按优先级返回结果有利于高效利用底层连接,提高用户体验。
然而,也不能过分迷信请求优先级,仍然要注意以下问题:

  • 服务端是否支持请求优先级
  • 会否引起队首阻塞问题,比如高优先级的慢响应请求会阻塞其他资源的交互。

4. 服务端推送

HTTP 2.0增加了服务端推送功能,服务端可以根据客户端的请求,提前返回多个响应,推送额外的资源给客户端。如下图所示,客户端请求stream 1,/page.html。服务端在返回stream 1消息的同时推送了stream 2(/script.js)和stream 4(/style.css)。

PUSH_PROMISE帧是服务端向客户端有意推送资源的信号。

  • 如果客户端不需要服务端Push,可在SETTINGS帧中设定服务端流的值为0,禁用此功能
  • PUSH_PROMISE帧中只包含预推送资源的首部。如果客户端对PUSH_PROMISE帧没有意见,服务端在PUSH_PROMISE帧后发送响应的DATA帧开始推送资源。如果客户端已经缓存该资源,不需要再推送,可以选择拒绝PUSH_PROMISE帧。
  • PUSH_PROMISE必须遵循请求-响应原则,只能借着对请求的响应推送资源。
    目前,Apache的mod_http2能够开启 H2Push on服务端推送Push。Nginx的ngx_http_v2_module还不支持服务端Push。
Apache mod_headers example
<Location /index.html>
    Header add Link "</css/site.css>;rel=preload"
    Header add Link "</images/logo.jpg>;rel=preload"
</Location>

5. 首部压缩

HTTP 1.x每一次通信(请求/响应)都会携带首部信息用于描述资源属性。HTTP 2.0在客户端和服务端之间使用“首部表”来跟踪和存储之前发送的键-值对。首部表在连接过程中始终存在,新增的键-值对会更新到表尾,因此,不需要每次通信都需要再携带首部。

另外,HTTP 2.0使用了首部压缩技术,压缩算法使用HPACK。可让报头更紧凑,更快速传输,有利于移动网络环境。
需要注意的是,HTTP 2.0关注的是首部压缩,而我们常用的gzip等是报文内容(body)的压缩。二者不仅不冲突,且能够一起达到更好的压缩效果。

6. 一个完整的HTTP 2.0通信过程

考虑一个问题,客户端如何知道服务端是否支持HTTP 2.0?是否支持对二进制分帧层的编码和解码?所以,在两端使用HTTP 2.0通信之前,必然存在协议协商的过程。

6.1 基于ALPN的协商过程

支持HTTP 2.0的浏览器可以在TLS会话层自发完成和服务端的协议协商以确定是否使用HTTP 2.0通信。其原理是TLS 1.2中引入了扩展字段,以允许协议的扩展,其中ALPN协议(Application Layer Protocol Negotiation, 应用层协议协商, 前身是NPN)用于客户端和服务端的协议协商过程。
服务端使用ALPN,监听443端口默认提供HTTP 1.1,并允许协商其他协议,比如SPDY和HTTP 2.0。
比如,客户端在TLS握手Client Hello阶段表明自身支持HTTP 2.0

服务端收到后,响应Server Hello,表示自己也支持HTTP 2.0。双方开始HTTP 2.0通信。

6.2 基于HTTP的协商过程

然而,HTTP 2.0一定是HTTPS(TLS 1.2)的特权吗?
当然不是,客户端使用HTTP也可以开启HTTP 2.0通信。只不过因为HTTP 1. 0和HTTP 2. 0都使用同一个 端口(80), 又没有服务器是否支持HTTP 2. 0的其他任何 信息,此时 客户端只能使用HTTP Upgrade机制(OkHttp, nghttp2等组件均可实现,也可以自己编码完成)通过协调确定适当的协议:

HTTP Upgrade request
GET / HTTP/1.1
host: nghttp2.org
connection: Upgrade, HTTP2-Settings
upgrade: h2c        /*发起带有HTTP2.0 Upgrade头部的请求*/       
http2-settings: AAMAAABkAAQAAP__   /*客户端SETTINGS净荷*/
user-agent: nghttp2/1.9.0-DEV

HTTP Upgrade response    
HTTP/1.1 101 Switching Protocols   /*服务端同意升级到HTTP 2.0*/
Connection: Upgrade
Upgrade: h2c

HTTP Upgrade success               /*协商完成*/

6.3 完整通信过程

TCP连接建立:

TLS握手和HTTP 2.0通信过程:

另外,在chrome中通过chrome://net-internals/#http2命令也能捕获HTTP 2.0通信过程:

42072: HTTP2_SESSION
textlink.simba.taobao.com:443 (PROXY 10.19.110.55:8080)
Start Time: 2017-04-05 11:39:11.459

t=370225 [st=    0] +HTTP2_SESSION  [dt=32475+]
                     --> host = "textlink.simba.taobao.com:443"
                     --> proxy = "PROXY 10.19.110.55:8080"
t=370225 [st=    0]    HTTP2_SESSION_INITIALIZED
                       --> protocol = "h2"
                       --> source_dependency = 42027 (PROXY_CLIENT_SOCKET_WRAPPER)
t=370225 [st=    0]    HTTP2_SESSION_SEND_SETTINGS
                       --> settings = ["[id:3 flags:0 value:1000]","[id:4 flags:0 value:6291456]","[id:1 flags:0 value:65536]"]
t=370225 [st=    0]    HTTP2_STREAM_UPDATE_RECV_WINDOW
                       --> delta = 15663105
                       --> window_size = 15728640
t=370225 [st=    0]    HTTP2_SESSION_SENT_WINDOW_UPDATE_FRAME
                       --> delta = 15663105
                       --> stream_id = 0
t=370225 [st=    0]    HTTP2_SESSION_SEND_HEADERS
                       --> exclusive = true
                       --> fin = true
                       --> has_priority = true
                       --> :method: GET
                           :authority: textlink.simba.taobao.com
                           :scheme: https
                           :path: /?name=tbhs&cna=IAj9EOy3fngCAXBQ5kJ9yusH&nn=&count=13&pid=430266_1006&_ksTS=1491363551394_94&callback=jsonp95
                           user-agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
                           accept: */*
                           referer: https://www.taobao.com/
                           accept-encoding: gzip, deflate, sdch, br
                           accept-language: zh-CN,zh;q=0.8
                           cookie: [382 bytes were stripped]
                       --> parent_stream_id = 0
                       --> stream_id = 1
                       --> weight = 147
t=370256 [st=   31]    HTTP2_SESSION_RECV_SETTINGS
                       --> host = "textlink.simba.taobao.com:443"
t=370256 [st=   31]    HTTP2_SESSION_RECV_SETTING
                       --> flags = 0
                       --> id = 3
                       --> value = 128
t=370256 [st=   31]    HTTP2_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE
                       --> delta_window_size = 2147418112
t=370256 [st=   31]    HTTP2_SESSION_RECV_SETTING
                       --> flags = 0
                       --> id = 4
                       --> value = 2147483647
t=370256 [st=   31]    HTTP2_SESSION_RECV_SETTING
                       --> flags = 0
                       --> id = 5
                       --> value = 16777215
t=370256 [st=   31]    HTTP2_SESSION_RECEIVED_WINDOW_UPDATE_FRAME
                       --> delta = 2147418112
                       --> stream_id = 0
t=370256 [st=   31]    HTTP2_SESSION_UPDATE_SEND_WINDOW
                       --> delta = 2147418112
                       --> window_size = 2147483647
t=370261 [st=   36]    HTTP2_SESSION_RECV_HEADERS
                       --> fin = false
                       --> :status: 200
                           date: Wed, 05 Apr 2017 03:39:11 GMT
                           content-type: text/html; charset=ISO-8859-1
                           vary: Accept-Encoding
                           server: Tengine
                           expires: Wed, 05 Apr 2017 03:39:11 GMT
                           cache-control: max-age=0
                           strict-transport-security: max-age=0
                           timing-allow-origin: *
                           content-encoding: gzip
                       --> stream_id = 1
t=370261 [st=   36]    HTTP2_SESSION_RECV_DATA
                       --> fin = false
                       --> size = 58
                       --> stream_id = 1
t=370261 [st=   36]    HTTP2_SESSION_UPDATE_RECV_WINDOW
                       --> delta = -58
                       --> window_size = 15728582
t=370261 [st=   36]    HTTP2_SESSION_RECV_DATA
                       --> fin = true
                       --> size = 0
                       --> stream_id = 1
t=370295 [st=   70]    HTTP2_STREAM_UPDATE_RECV_WINDOW
                       --> delta = 58
                       --> window_size = 15728640
t=402700 [st=32475]

7. HTTP 2.0性能瓶颈

是不是启用HTTP 2.0后性能必然提升了?任何事情都不是绝对的,虽然总体而言性能肯定是能提升的。
我想HTTP 2.0会带来新的性能瓶颈。因为现在所有的压力集中在底层一个TCP连接之上,TCP很可能就是下一个性能瓶颈,比如TCP分组的队首阻塞问题,单个TCP packet丢失导致整个连接阻塞,无法逃避,此时所有消息都会受到影响。未来,服务器端针对HTTP 2.0下的TCP配置优化至关重要,有机会我们再跟进详述。

参考文献

《Web性能权威指南》
《使用 nghttp2 调试 HTTP/2 流量》 https://imququ.com/post/intro-to-nghttp2.html

来自:https://blog.csdn.net/zhuyiquan/article/details/69257126

http协议-http1.1协议分析

学习Web开发不好好学习HTTP报文,将会“打拳不练功,到老一场空”,你花在犯迷糊上的时间比你沉下心来学习HTTP的时间肯定会多很多。

HTTP请求报文解剖

HTTP请求报文由3部分组成(请求行+请求头+请求体):

 

下面是一个实际的请求报文:

①是请求方法,GET和POST是最常见的HTTP方法,除此以外还包括DELETE、HEAD、OPTIONS、PUT、TRACE。不过,当前的大多数浏览器只支持GET和POST,Spring 3.0提供了一个HiddenHttpMethodFilter,允许你通过“_method”的表单参数指定这些特殊的HTTP方法(实际上还是通过POST提交表单)。服务端配置了HiddenHttpMethodFilter后,Spring会根据_method参数指定的值模拟出相应的HTTP方法,这样,就可以使用这些HTTP方法对处理方法进行映射了。

②为请求对应的URL地址,它和报文头的Host属性组成完整的请求URL,③是协议名称及版本号。

④是HTTP的报文头,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息。

⑤是报文体,它将一个页面表单中的组件值通过param1=value1&param2=value2的键值对形式编码成一个格式化串,它承载多个请求参数的数据。不但报文体可以传递请求参数,请求URL也可以通过类似于“/chapter15/user.html? param1=value1&param2=value2”的方式传递请求参数。

对照上面的请求报文,我们把它进一步分解,你可以看到一幅更详细的结构图:

引用
HttpWatch是强大的网页数据分析工具,安装后将集成到Internet Explorer工具栏中。它不用代理服务器或一些复杂的网络监控工具,就能抓取请求及响应的完整信息,包括Cookies、消息头、查询参数、响应报文等,是Web应用开发人员的必备工具。

HTTP请求报文头属性

报文头属性是什么东西呢?我们不妨以一个小故事来说明吧。

引用
快到中午了,张三丰不想去食堂吃饭,于是打电话叫外卖:老板,我要一份[鱼香肉丝],要12:30之前给我送过来哦,我在江湖湖公司研发部,叫张三丰。

这里,你要[鱼香肉丝]相当于HTTP报文体,而“12:30之前送过来”,你叫“张三丰”等信息就相当于HTTP的报文头。它们是一些附属信息,帮忙你和饭店老板顺利完成这次交易。

请求HTTP报文和响应HTTP报文都拥有若干个报文关属性,它们是为协助客户端及服务端交易的一些附属信息。

常见的HTTP请求报文头属性

Accept

请求报文可通过一个“Accept”报文头属性告诉服务端 客户端接受什么类型的响应。

如下报文头相当于告诉服务端,俺客户端能够接受的响应类型仅为纯文本数据啊,你丫别发其它什么图片啊,视频啊过来,那样我会歇菜的~~~:

Accept:text/plain  

Accept属性的值可以为一个或多个MIME类型的值,关于MIME类型,大家请参考:http://en.wikipedia.org/wiki/MIME_type

Cookie

客户端的Cookie就是通过这个报文头属性传给服务端的哦!如下所示:

Cookie: $Version=1; Skin=new;jsessionid=5F4771183629C9834F8382E23BE13C4C

服务端是怎么知道客户端的多个请求是隶属于一个Session呢?注意到后台的那个jsessionid=5F4771183629C9834F8382E23BE13C4C木有?原来就是通过HTTP请求报文头的Cookie属性的jsessionid的值关联起来的!(当然也可以通过重写URL的方式将会话ID附带在每个URL的后面哦)。

Referer

表示这个请求是从哪个URL过来的,假如你通过google搜索出一个商家的广告页面,你对这个广告页面感兴趣,鼠标一点发送一个请求报文到商家的网站,这个请求报文的Referer报文头属性值就是http://www.google.com。

引用
唐僧到了西天.
如来问:侬是不是从东土大唐来啊?
唐僧:厉害!你咋知道的!
如来:呵呵,我偷看了你的Referer…

很多貌似神奇的网页监控软件(如著名的 我要啦),只要在你的网页上放上一段JavaScript,就可以帮你监控流量,全国访问客户的分布情况等报表和图表,其原理就是通过这个Referer及其它一些HTTP报文头工作的。

Cache-Control

对缓存进行控制,如一个请求希望响应返回的内容在客户端要被缓存一年,或不希望被缓存就可以通过这个报文头达到目的。

如以下设置,相当于让服务端将对应请求返回的响应内容不要在客户端缓存:

Cache-Control: no-cache

其它请求报文头属性

参见:http://en.wikipedia.org/wiki/List_of_HTTP_header_fields

如何访问请求报文头

由于请求报文头是客户端发过来的,服务端当然只能读取了,以下是HttpServletRequest一些用于读取请求报文头的API:

//获取请求报文中的属性名称  
java.util.Enumeration<java.lang.String>   getHeaderNames();  
  
//获取指定名称的报文头属性的值  
java.lang.String getHeader(java.lang.String name)

由于一些请求报文头属性“太著名”了,因此HttpServletRequest为它们提供了VIP的API:

//获取报文头中的Cookie(读取Cookie的报文头属性)  
 Cookie[]   getCookies() ;  
  
//获取客户端本地化信息(读取 Accept-Language 的报文头属性)  
java.util.Locale    getLocale()   
  
//获取请求报文体的长度(读取Content-Length的报文头属性)  
int getContentLength();

HttpServletRequest可以通过

HttpSession getSession()

获取请求所关联的HttpSession,其内部的机理是通过读取请求报文头中Cookie属性的JSESSIONID的值,在服务端的一个会话Map中,根据这个JSESSIONID获取对应的HttpSession的对象。(这样,你就不会觉得HttpSession很神秘了吧,你自己也可以做一个类似的会话管理  )

HTTP响应报文解剖

响应报文结构

HTTP的响应报文也由三部分组成(响应行+响应头+响应体):

以下是一个实际的HTTP响应报文:

①报文协议及版本;
②状态码及状态描述;
③响应报文头,也是由多个属性组成;
④响应报文体,即我们真正要的“干货”。

响应状态码

和请求报文相比,响应报文多了一个“响应状态码”,它以“清晰明确”的语言告诉客户端本次请求的处理结果。

HTTP的响应状态码由5段组成:

  • 1xx 消息,一般是告诉客户端,请求已经收到了,正在处理,别急…
  • 2xx 处理成功,一般表示:请求收悉、我明白你要的、请求已受理、已经处理完成等信息.
  • 3xx 重定向到其它地方。它让客户端再发起一个请求以完成整个处理。
  • 4xx 处理发生错误,责任在客户端,如客户端的请求一个不存在的资源,客户端未被授权,禁止访问等。
  • 5xx 处理发生错误,责任在服务端,如服务端抛出异常,路由出错,HTTP版本不支持等。

以下是几个常见的状态码:

200 OK

你最希望看到的,即处理成功!

303 See Other

我把你redirect到其它的页面,目标的URL通过响应报文头的Location告诉你。

引用
悟空:师傅给个桃吧,走了一天了
唐僧:我哪有桃啊!去王母娘娘那找吧

304 Not Modified

告诉客户端,你请求的这个资源至你上次取得后,并没有更改,你直接用你本地的缓存吧,我很忙哦,你能不能少来烦我啊!

404 Not Found

你最不希望看到的,即找不到页面。如你在google上找到一个页面,点击这个链接返回404,表示这个页面已经被网站删除了,google那边的记录只是美好的回忆。

500 Internal Server Error

看到这个错误,你就应该查查服务端的日志了,肯定抛出了一堆异常,别睡了,起来改BUG去吧!

其它的状态码参见:http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

有些响应码,Web应用服务器会自动给生成。你可以通过HttpServletResponse的API设置状态码:

//设置状态码,状态码在HttpServletResponse中通过一系列的常量预定义了,如SC_ACCEPTED,SC_OK  
void    setStatus(int sc)

常见的HTTP响应报文头属性

Cache-Control

响应输出到客户端后,服务端通过该报文头属告诉客户端如何控制响应内容的缓存。

下面,的设置让客户端对响应内容缓存3600秒,也即在3600秒内,如果客户再次访问该资源,直接从客户端的缓存中返回内容给客户,不要再从服务端获取(当然,这个功能是靠客户端实现的,服务端只是通过这个属性提示客户端“应该这么做”,做不做,还是决定于客户端,如果是自己宣称支持HTTP的客户端,则就应该这样实现)。

Cache-Control: max-age=3600

ETag

一个代表响应服务端资源(如页面)版本的报文头属性,如果某个服务端资源发生变化了,这个ETag就会相应发生变化。它是Cache-Control的有益补充,可以让客户端“更智能”地处理什么时候要从服务端取资源,什么时候可以直接从缓存中返回响应。

关于ETag的说明,你可以参见:http://en.wikipedia.org/wiki/HTTP_ETag
Spring 3.0还专门为此提供了一个org.springframework.web.filter.ShallowEtagHeaderFilter(实现原理很简单,对JSP输出的内容MD5,这样内容有变化ETag就相应变化了),用于生成响应的ETag,因为这东东确实可以帮助减少请求和响应的交互。

下面是一个ETag:

ETag: "737060cd8c284d8af7ad3082f209582d"

Location

我们在JSP中让页面Redirect到一个某个A页面中,其实是让客户端再发一个请求到A页面,这个需要Redirect到的A页面的URL,其实就是通过响应报文头的Location属性告知客户端的,如下的报文头属性,将使客户端redirect到iteye的首页中:

Location: http://www.iteye.com

Set-Cookie

服务端可以设置客户端的Cookie,其原理就是通过这个响应报文头属性实现的:

Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1

其它HTTP响应报文头属性

更多其它的HTTP响应头报文,参见:http://en.wikipedia.org/wiki/List_of_HTTP_header_fields

如何写HTTP请求报文头

在服务端可以通过HttpServletResponse的API写响应报文头的属性:

//添加一个响应报文头属性  
void    setHeader(String name, String value)

象Cookie,Location这些响应都是有福之人,HttpServletResponse为它们都提供了VIP版的API:

//添加Cookie报文头属性  
void addCookie(Cookie cookie)   
  
//不但会设置Location的响应报文头,还会生成303的状态码呢,两者天仙配呢  
void    sendRedirect(String location)

来自:https://blog.csdn.net/u010256388/article/details/68491509