HTTP协议的报文内容以及一次完整的HTTP请求流程【一万字】

518 阅读34分钟

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

介绍了HTTP协议的报文,包括请求报文和响应报文,以及报文首部、请求方法、Cookie等相关概念,以及一次完整的HTTP请求流程。

前面我们简单学习了HTTP协议的相关概念,现在我们来介绍HTTP协议的报文,包括请求报文和响应报文,以及报文首部、请求方法、Cookie等相关概念。

用于HTTP协议交互的信息被称为HTTP报文。请求端(客户端)的HTTP报文叫做请求报文,响应端(服务器端)的叫做响应报文。HTTP 报文本身是由多行(用 CR+LF 作换行符)数据构成的字符串文本。

HTTP报文大致可以分为报文首部和报文主体两块。两者由最初出现的空行(CR+LF)来划分。通常,并不一定要有报文主体。

在这里插入图片描述

1 请求报文

HTTP 协议规定,请求从客户端发出,最后服务器端响应该请求并返回。换句话说,肯定是先从客户端开始建立通信的,服务器端在没有接收到请求之前不会发送响应。

请求报文的格式如下:

在这里插入图片描述

简化为:

请求首行 请求头信息 请求空行 请求体

请求首行和请求头共同构成了HTTP请求首部!浏览器发送给服务器的内容就这个格式的,如果不是这个格式服务器将无法解读!

一个GET请求报文如下:

GET /hello/index.jsp HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Cookie: JSESSIONID=369766FDF6220F7803433C0B2DE36D98

一个POST请求报文如下:

POST /hello/index.jsp HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, */*
Referer: http://localhost:8080/hello/index.jsp
Accept-Language: zh-cn,en-US;q=0.5
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; InfoPath.2; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost:8080
Content-Length: 13
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=E365D980343B9307023A1D271CC48E7D

keyword=hello

相关参数解释如下:

  1. 请求首行:第一行数据
    1. GET /hello/index?num=8 HTTP/1.1。表示请求方法、请求的资源(URL)地址、请求的协议和版本。案例中的含义就是:GET请求,请求服务器路径为/hello/index,请求协议和版本号为http1.1。同时GET请求的URL后面还附带了请求的参数num=8。
  2. 请求头:key-value的形式,value也可以使用key-value传递多个数据,使用“;”分隔:
    1. Host:localhost。表示接受请求的服务器地址(请求的主机地址),可以是IP:端口号,也可以是域名。案例中的含义就是:localhost,即本机。
    2. Connection: keep-alive。指定的连接相关的属性。案例中的含义就是:保持一段时间连接,默认就为3000ms;
    3. Accept: application/json, text/plain, /。告诉服务器当前客户端可以接收的文档类型,其实这里包含了*/*,就表示什么都可以接收;
    4. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36。与浏览器和OS相关的信息。有些网站会显示用户的系统版本和浏览器版本信息,这都是通过获取User-Agent头信息而来的;
    5. Referer: www.baidu.com/。请求来自哪个页面,例…
    6. Accept-Encoding: gzip, deflate, br。支持的压缩格式。数据在网络上传递时,可能服务器会把数据压缩后再发送;
    7. Accept-Language: zh-CN,zh;q=0.9。当前客户端支持的语言,可以在浏览器的工具-选项中找到语言相关信息;
    8. Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7。客户端支持的编码;
    9. Cookie: PSTM=1594605101;JSESSIONID=369766FDF622xx。用于在客户端缓存一些信息,通常用于服务器的会话功能(session)的客户端实现。比如存储用户登录信息,实现跳转免登录,后面会专门讲解。
    10. Content-Type: application/json;charset=UTF-8。请求和响应中的媒体类型信息(数据类型)。用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析并展示html等。这里的application/json;charset=UTF-8表示JSON格式的数据交互,这是前后端分离开发的常用数据格式。
    11. Content-Length:13。请求体的长度,这里表示13个字节。
  3. 请求空行(CR+LF):用来分隔请求头和请求体的数据。
  4. 请求体:POST请求是可以有体的,就是POST请求提交的数据,而GET请求不能有请求体,它的请求的数据会附在url之后。

1.1 Referer请求头

Referer请求头是比较有用的一个请求头,它可以用来做统计工作,也可以用来做防盗链。

统计工作: 我公司网站在百度上做了广告,但不知道在百度上做广告对我们网站的访问量是否有影响,那么可以对每个请求中的Referer进行分析,如果Referer为百度的很多,那么说明用户都是通过百度找到我们公司网站的。

防盗链: 我公司网站上有一个下载链接,而其他网站盗链了这个地址,例如在我网站上的index.html页面中有一个链接,点击即可下载JDK7.0,但有某个人的微博中盗链了这个资源,它也有一个链接指向我们网站的JDK7.0,也就是说登录它的微博,点击链接就可以从我网站上下载JDK7.0,这导致我们网站的广告没有看,但下载的却是我网站的资源。这时可以使用Referer进行防盗链,在资源被下载之前,我们对Referer进行判断,如果请求来自本网站,那么允许下载,如果非本网站,先跳转到本网站看广告,然后再允许下载。

1.2 GET和POST提交的区别

来自w3schools(www.w3school.com.cn/tags/html_r…

GET POST
后退按钮/刷新 无害 数据会被重新提交(浏览器应该告知用户数据会被重新提交)。
书签 可收藏为书签 不可收藏为书签
缓存 能被缓存 不能缓存
编码类型 application/x-www-form-urlencoded application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。
历史 参数保留在浏览器历史中。 参数不会保存在浏览器历史中。
对数据长度的限制 是的。当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。 无限制。
对数据类型的限制 只允许 ASCII 字符。 没有限制。也允许二进制数据。
安全性 与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET ! POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。
可见性 数据在 URL 中对所有人都是可见的。 数据不会显示在 URL 中。

2 响应报文

接收到请求的服务器,会将请求内容的处理结果以响应的形式返回。响应报文格式如下:

在这里插入图片描述

简化为:

响应首行 响应头信息 响应空行 响应体

响应首行和响应头共同构成了HTTP响应首部!

响应内容是由服务器发送给浏览器的内容,浏览器会根据响应内容来显示。

  1. 响应首行
    1. HTTP/1.1 200 OK。包括了响应协议、状态码、以及解释。该案例表示响应协议为HTTP1.1,状态码为200,表示请求成功,OK是对状态码的解释;
  2. 响应头信息
    1. Server: Apache-Coyote/1.1。服务器的版本信息;
    2. Content-Type: text/html;charset=UTF-8。将会响应html文本类型的数据,响应体使用的编码为UTF-8;前后端分离开发时常用的就是application/json。
    3. Content-Length: 724。响应体为724字节;
    4. Set-Cookie: JSESSIONID=C97E2B4C55xx; Path=/hello。响应给客户端的Cookie;
    5. Date: Wed, 25 Sep 2012 04:15:03 GMT。响应的时间,这可能会有8小时的时区差;
  3. 响应空行:区分响应头和响应体
  4. 响应体:返回给客户端(浏览器)的数据,下面的案例中返回的是一个HTML页面,从Content-Type: text/html;charset=UTF-8中能确定响应类型。

以下是一个常见的响应报文,响应内容为一个HTML页面:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=UTF-8
Content-Length: 724
Set-Cookie: JSESSIONID=C97E2B4C55553EAB46079A4F263435A4; Path=/hello
Date: Wed, 25 Sep 2012 04:15:03 GMT

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="http://localhost:8080/hello/">
    
    <title>My JSP 'index.jsp' starting page</title>
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->
  </head>
  
  <body>
<form action="" method="post">
  关键字:<input type="text" name="keyword"/>
  <input type="submit" value="提交"/>
</form>
  </body>
</html>

2.1 响应状态码

来自w3c:www.w3cschool.cn/http/g9prxf…

当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码(HTTP Status Code)的信息头(server header)用以响应浏览器的请求。

HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型:

分类 分类描述
1** 信息,服务器收到请求,需要请求者继续执行操作
2** 成功,操作被成功接收并处理
3** 重定向,需要进一步的操作以完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,服务器在处理请求的过程中发生了错误

2.1.1 常见响应码

  1. 200:请求被正常处理
  2. 204:请求被受理但没有资源可以返回
  3. 206:客户端只是请求资源的一部分,服务器只对请求的部分资源执行GET方法,响应报文中通过Content-Range指定范围的资源。
  4. 301:永久性重定向
  5. 302:临时重定向
  6. 303:与302状态码有相似功能,只是它希望客户端在请求一个URI的时候,能通过GET方法重定向到另一个URI上。
  7. 304:发送附带条件的请求时,条件不满足时返回,与重定向无关
  8. 307:临时重定向,与302类似,只是强制要求使用POST方法
  9. 400:请求报文语法有误,服务器无法识别
  10. 401:请求需要认证
  11. 403:请求的对应资源禁止被访问
  12. 404:服务器无法找到对应资源
  13. 500:服务器内部错误
  14. 503:服务器正忙

2.1.2 响应状态码列表

状态码 状态码英文名称 中文描述
100 Continue 继续。客户端应继续其请求
101 Switching Protocols 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
200 OK 请求成功。一般用于GET与POST请求
201 Created 已创建。成功请求并创建了新的资源
202 Accepted 已接受。已经接受请求,但未处理完成
203 Non-Authoritative Information 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
204 No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
205 Reset Content 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
206 Partial Content 部分内容。服务器成功处理了部分GET请求
300 Multiple Choices 多种选择。请求的资源可包括多个位置,响应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
301 Moved Permanently 永久移动(重定向)。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302 Found 临时移动(重定向)。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
303 See Other 查看其它地址。与301类似。使用GET和POST请求查看
304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
305 Use Proxy 使用代理。所请求的资源必须通过代理访问
306 Unused 已经被废弃的HTTP状态码
307 Temporary Redirect 临时重定向。与302类似。使用GET请求重定向
400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
402 Payment Required 保留,将来使用
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
405 Method Not Allowed 客户端采用的请求中的方法被禁止.
406 Not Acceptable 服务器无法根据客户端请求的内容特性完成请求
407 Proxy Authentication Required 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
408 Request Time-out 服务器等待客户端发送的请求时间过长,超时
409 Conflict 服务器完成客户端的PUT请求是可能返回此代码,服务器处理请求时发生了冲突
410 Gone 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
411 Length Required 服务器无法处理客户端发送的不带Content-Length的请求信息
412 Precondition Failed 客户端请求信息的先决条件错误
413 Request Entity Too Large 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
414 Request-URI Too Large 请求的URI过长(URI通常为网址),服务器无法处理
415 Unsupported Media Type 服务器无法处理请求附带的媒体格式
416 Requested range not satisfiable 客户端请求的范围无效
417 Expectation Failed 服务器无法满足Expect的请求头信息
500 Internal Server Error 服务器内部错误,无法完成请求
501 Not Implemented 服务器不支持请求的功能,无法完成请求
502 Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求
505 HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理

2.2 304响应码

当用户第一次请求index.html时,服务器会添加一个名为Last-Modified响应头,这个头说明了index.html的最后修改时间,浏览器会把index.html内容,以及最后响应时间缓存下来。

当用户第二次请求index.html时,在请求中包含一个名为If-Modified-Since请求头,它的值就是第一次请求时服务器通过Last-Modified响应头发送给浏览器的值,即index.html最后的修改时间,If-Modified-Since请求头就是在告诉服务器,我这里浏览器缓存的index.html最后修改时间是这个,您看看现在的index.html最后修改时间是不是这个,如果还是,那么您就不用再响应这个index.html内容了,我会把缓存的内容直接显示出来。而服务器端会获取If-Modified-Since值,与index.html的当前最后修改时间比对,如果相同,服务器会发响应码304,表示index.html与浏览器上次缓存的相同,无需再次发送,浏览器可以显示自己的缓存页面,如果比对不同,那么说明index.html已经做了修改,服务器会响应200。 在这里插入图片描述

  1. 请求头
    1. If-Modified-Since:把上次请求的index.html的最后修改时间还给服务器。
  2. 响应头
    1. Last-Modified:最后的修改时间;
    2. 304状态码:比较If-Modified-Since的时间与index.html的当前最后修改时间比对一样时,服务器会响应304,而且不会有响正文,表示浏览器缓存的就是最新版本!

2.3 其他响应头

告诉浏览器不要缓存的响应头:

Expires: 0;
Pragma: no-cache;
Cache-Control: no-cache;

自动刷新(请求)的响应头,告诉浏览器在3秒之后请求www.baidu.cn

Refresh:3;url=https://www.baidu.cn

3 报文首部

HTTP 协议的请求和响应报文中必定包含 HTTP 首部。首部内容为客户端和服务器分别处理请求和响应提供所需要的信息。对于客户端用户来说,这些信息中的大部分内容都无须亲自查看。使用首部字段是为了给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容。

HTTP 首部字段是由首部字段名和字段值构成的,中间用冒号“:” 分隔。另外,字段值对应单个 HTTP 首部字段可以有多个值,如下:

Keep-Alive: timeout=15, max=100

若 HTTP 首部字段重复了会如何?这种情况在规范内尚未明确,根据浏览器内部处理逻辑的不同,结果可能并不一致。有些浏览器会优先处理第一次出现的首部字段,而有些则会优先处理最后出现的首部字段。

3.1 HTTP 首部字段类型

HTTP 首部字段根据实际用途被分为以下 4 种类型。

3.1.1 通用首部字段(General Header Fields)

请求报文和响应报文两方都可以使用的首部。

首部字段名 说明
Cache-Control 控制缓存的行为,一般包括一个“max-age=3400”的值,代表缓存的有效时间为资源返回后的3400秒之内
Connection 逐跳首部、连接的管理。如果值为其他字段的名字,代表代理服务器转发时将不再携带该字段。如果值为close或Keep-Alive则分别表示连接为短/长连接
Date 创建报文的日期时间
Pragma 报文指令。是HTTP/1.1之前版本的遗留字段,仅作为与HTTP/1.0的向后兼容而定义
Trailer 报文末端的首部一览
Transfer-Encoding 指定报文主体的传输编码方式
Upgrade 升级为其他协议
Via 代理服务器的相关信息。报文经过代理或网关时,会先在首部字段Via中附加该服务器的信息,然后再进行转发,目的是追踪请求和响应报文的传输路径
Warning 错误通知

3.1.2 请求首部字段(Request Header Fields)

从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。

首部字段名 说明
Accept 用户代理可处理的媒体类型
Accept-Charset 优先的字符集
Accept-Encoding 优先的内容编码
Authorization Web认证信息
Expect 期待服务器的特定行为
From 用户的电子邮箱地址
Host 请求资源所在的服务器主机名/域名
If-Match 比较实体标记(Etag)
If-Modified-Since 比较资源的更新时间,出现在条件get请求中
If-None-Match 比较实体标记(与If-Match相反)
If-Range 资源未更新时发送实体Byte的范围请求
If-Unmodified-Since 比较资源的更新时间(与If-Modified-Since相反)
Max-Forwards 最大传输逐跳数
Proxy-Authorization 代理服务器要求客户端的认证信息
Range 实体的字节范围请求
Referer 请求中URI的原始获取方
TE 传输编码的优先级
User-Agent HTTP客户端程序的信息。如果是浏览器则是对应浏览器的用户代理字符串

3.1.3 响应首部字段(Response Header Fields)

从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。

首部字段名 说明
Accept-Ranges 是否接受字节范围请求
Age 推算资源创建经过时间
ETag 资源的匹配信息
Location 令客户端重定向至指定URI
Proxy-Authenticate 代理服务器对客户端的认证信息
Server HTTP服务器的安装信息
Vary 代理服务器缓存的管理信息
WWW-Authenticate 服务器对客户端的认证信息

3.1.4 实体首部字段(Entity Header Fields)

针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息。

首部字段名 说明
Allow 资源可支持的HTTP方法
Content-Encoding 实体主体适用的编码方式
Content-language 实体主体的自然语言
Content-length 实体主体的大小(单位:字节)
Content-MD5 实体主体的报文摘要
Content-Range 实体主体的位置范围
Content-Type 实体主体的媒体类型
Expires 实体主体过期的日期时间
Last-Modified 资源的最后修改日期时间

3.2 非 HTTP/1.1 首部字段

在 HTTP 协议通信交互中使用到的首部字段,不限于 RFC2616 中定义的 47 种首部字段。还有 Cookie、Set-Cookie 和 Content-Disposition等在其他 RFC 中定义的首部字段,它们的使用频率也很高。

这些非正式的首部字段统一归纳在 RFC4229 HTTP Header Field Registrations 中。

3.3 End-to-end 首部和 Hop-by-hop 首部

HTTP 首部字段将定义成缓存代理和非缓存代理的行为,分成 2 种类型:

  1. 端到端首部(End-to-end Header):分在此类别中的首部会转发给请求/响应对应的最终接收目标,且必须保存在由缓存生成的响应中,另外规定它必须被转发。
  2. 逐跳首部(Hop-by-hop Header):分在此类别中的首部只对单次转发有效,会因通过缓存或代理而不再转发。HTTP/1.1 和之后版本中,如果要使用 hop-by-hop 首部,需提供 Connection 首部字段。

下面列举了 HTTP/1.1 中的逐跳首部字段。除这 8 个首部字段之外,其他所有字段都属于端到端首部。

Connection、Keep-Alive、Proxy-Authenticate、Proxy-Authorization、Trailer、TE、Transfer-Encoding、Upgrade

3.4 为 Cookie 服务的首部字段

管理服务器与客户端之间状态的 Cookie,虽然没有被编入标准化HTTP/1.1 的 RFC2616 中,但在 Web 网站方面得到了广泛的应用。

Cookie 的工作机制是用户识别及状态管理。Web 网站为了管理用户的状态会通过 Web 浏览器,把一些数据临时写入用户的计算机内。接着当用户访问该Web网站时,可通过通信方式取回之前发放的Cookie。

调用 Cookie 时,由于可校验 Cookie 的有效期,以及发送方的域、路径、协议等信息,所以正规发布的 Cookie 内的数据不会因来自其他Web 站点和攻击者的攻击而泄露。

为 Cookie 服务的首部字段如下:

首部字段名 说明 首部类型
Set-Cookie 开始状态管理所使用的Cookie信息 响应首部字段
Cookie 服务器接收到的Cookie信息 请求首部字段

3.4.1 Set-Cookie

简单的示例如下:

Set-Cookie: status=enable; expires=Tue, 05 Jul 2011 07:26:31

当服务器准备开始管理客户端的状态时,会事先告知各种信息。下面的表格列举了响应首部字段Set-Cookie 的字段值。

属性 说明
NAME=VALUE 赋予Cookie的名称和其值(必需项)
expires=DATE Cookie的有效期(若不明确指定则默认为浏览器关闭前为止,即内存Cookie)另外,一旦 Cookie 从服务器端发送至客户端,服务器端就不存在可以显式删除 Cookie 的方法。但可通过覆盖已过期的 Cookie,实现对客户端 Cookie 的实质性删除操作。 后面学习Servlet的时候我们就知道,通过cookie.setMaxAge()方法设置的就是Cookie的expires属性。
path=PATH 将服务器上的资源路径目录作为Cookie的适用对象(若不指定则默认为当前URL资源所在的目录)。 后面学习Servlet的时候我们就知道,通过cookie.setPath()方法设置的就是Cookie的path属性。
domain=域名 作为Cookie适用对象的域名(若不指定则默认为创建Cookie的服务器的域名)。 后面学习Servlet的时候我们就知道,通过cookie.setDomain()方法设置的就是Cookie的domain属性。
Secure 仅在HTTPS安全通信时才会发送Cookie
HttpOnly 加以限制,使Cookie不能被JavaScript脚本访问

3.4.2 Cookie

简单的示例如下:

Cookie: status=enable

请求首部字段 Cookie 会告知服务器,当客户端想获得 HTTP 状态管理支持时,就会在请求中包含从服务器接收到的 Cookie。接收到多个Cookie 时,同样可以以多个 Cookie 形式发送。

2.4 HTTP方法

HTTP 方法用于告知服务器该请求的意图,该信息位于请求首行。常用的有POST和GET方法,GET是用来获取数据的,POST是用来提交数据的。根据 HTTP 标准,HTTP 请求可以使用多种请求方法。如今RESTFUL风格的接口,就是对于HTTP协议这些请求方法的充分利用!

HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD方法;

HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法,同时废弃了LINK和UNLINK方法。目前基本上都是使用的HTTP1.1。

HTTP/1.0 和 HTTP/1.1 支持的方法:

方法 说明 支持的HTTP协议版本
GET 获取资源 1.0、1.1
POST 新建资源,可以表示修改 1.0、1.1
PUT 修改资源 1.0、1.1
DELETE 删除资源 1.0、1.1
HEAD 类似与GET,获得报文首部,不返回报文主体 1.0、1.1
OPTIONS 询问资源支持的请求方法 1.1
TRACE 追踪路径 1.1
CONNECT 要求用隧道协议连接代理 1.1
LINK 建立和资源之间的联系 1.0
UNLINK 断开连接关系 1.0

LINK 和 UNLINK 已被 HTTP/1.1 废弃,不再支持。

2.5 编码提升传输效率

HTTP 在传输数据时可以按照数据原貌直接传输,但也可以在传输过程中通过编码提升传输速率。通过在传输时编码,能有效地处理大量的访问请求。但是,编码的操作需要计算机来完成,因此会消耗更多的 CPU 等资源。

2.5.1 报文主体和实体主体

报文(message)是 HTTP 通信中的基本单位,由 8 位组字节流(octet sequence,其中 octet 为 8 个比特)组成,通过 HTTP 通信传输。

实体(entity)作为请求或响应的有效载荷数据(补充项)被传输,其内容由实体首部和实体主体组成,实体首部补充了资源内容更新时间等与实体有关的信息,则HTTP报文的主体用于传输请求或响应的实体主体。

关于HTTP报文和实体的关系,通常情况下,报文首部包括实体首部(报文首部部分有讲过),报文主体等于实体主体。只有当传输中进行编码操作时,实体主体的内容发生变化,才导致它和报文主体产生差异。

2.5.2 压缩传输的内容编码

向待发送邮件内增加附件时,为了使邮件容量变小,我们会先用 ZIP压缩文件之后再添加附件发送。HTTP 协议中有一种被称为内容编码的功能也能进行类似的操作。

内容编码指明应用在实体内容上的编码格式,并保持实体信息原样压缩。内容编码后的实体由客户端接收并负责解码。

常用的内容编码有以下几种:

  1. gzip(GNU zip)
  2. compress(UNIX 系统的标准压缩)
  3. deflate(zlib)
  4. identity(不进行编码)

在这里插入图片描述

2.5.3 分割发送的分块传输编码

在 HTTP 通信过程中,请求的编码实体资源尚未全部传输完成之前,浏览器无法显示请求页面。在传输大容量数据时,通过把数据分割成多块,能够让浏览器逐步显示页面。

这种把实体主体分块的功能称为分块传输编码(Chunked TransferCoding)。

在这里插入图片描述

分块传输编码会将实体主体分成多个部分(块)。每一块都会用十六进制来标记块的大小,而实体主体的最后一块会使用“0(CR+LF)”来标记。

使用分块传输编码的实体主体会由接收的客户端负责解码,恢复到编码前的实体主体。

HTTP/1.1 中存在一种称为传输编码(Transfer Coding)的机制,它可以在通信时按某种编码方式传输,但只定义作用于分块传输编码中。

2.6 发送多种数据的多部分对象集合

在这里插入图片描述

发送邮件时,我们可以在邮件里写入文字并添加多份附件。这是因为采用了 MIME(Multipurpose Internet Mail Extensions,多用途因特网邮件扩展)机制,它允许邮件处理文本、图片、视频等多个不同类型的数据。例如,图片等二进制数据以 ASCII 码字符串编码的方式指明, 就是利用 MIME 来描述标记数据类型。而在 MIME 扩展中会使用一种称为多部分对象集合(Multipart)的方法,来容纳多份不同类型的数据。

相应地,HTTP 协议中也采纳了多部分对象集合,发送的一份报文主体内可含有多类型实体。通常是在图片或文本文件等上传时使用。

多部分对象集合包含的对象如下:

  1. multipart/form-data。在 Web 表单文件上传时使用。
Content-Type: multipart/form-data; boundary=AaB03x

--AaB03x
Content-Disposition: form-data; name="field1"

Joe Blow

--AaB03x
Content-Disposition: form-data; name="pics"; filename="file1.txt"
Content-Type: text/plain

...(file1.txt的数据)...
--AaB03x--
  1. multipart/byteranges。状态码 206(Partial Content,部分内容)响应报文包含了多个范围的内容时使用。
HTTP/1.1 206 Partial Content
Date: Fri, 13 Jul 2012 02:45:26 GMT
Last-Modified: Fri, 31 Aug 2007 02:02:20 GMT
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES

--THIS_STRING_SEPARATES
Content-Type: application/pdf
Content-Range: bytes 500-999/8000

...(范围指定的数据)...
--THIS_STRING_SEPARATES
Content-Type: application/pdf
Content-Range: bytes 7000-7999/8000

...(范围指定的数据)...
--THIS_STRING_SEPARATES--

在 HTTP 报文中使用多部分对象集合时,需要在首部字段里加上Content-type。

boundary 字符串指定的各个实体的起始行之前插入“--”标记(例如:--AaB03x、--THIS_STRING_SEPARATES),而在多部分对象集合对应的字符串的最后插入“--”标记(例如:--AaB03x--、--THIS_STRING_SEPARATES--)作为结束。

多部分对象集合的每个部分类型中,都可以含有首部字段。另外,可以在某个部分中嵌套使用多部分对象集合。有关多部分对象集合更详细的解释,请参考 RFC2046

2.7 获取部分内容的范围请求

以前,用户不能使用现在这种高速的带宽访问互联网,当时,下载一个尺寸稍大的图片或文件就已经很吃力了。如果下载过程中遇到网络中断的情况,那就必须重头开始。为了解决上述问题,需要一种可恢复的机制。所谓恢复是指能从之前下载中断处恢复下载。

要实现该功能需要指定下载的实体范围。像这样,指定范围发送的请求叫做范围请求(Range Request)。

对一份 10 000 字节大小的资源,如果使用范围请求,可以只请求5001~10 000 字节内的资源。

在这里插入图片描述

执行范围请求时,会用到首部字段 Range 来指定资源的 byte 范围。byte 范围的指定形式如下。

  1. 5001~10 000 字节:Range: bytes=5001-10000
  2. 从 5001 字节之后全部的:Range: bytes=5001-
  3. 从一开始到 3000 字节和 5000~7000 字节的多重范围:Range: bytes=-3000, 5000-7000

针对范围请求,响应会返回状态码为 206 Partial Content 的响应报文。另外,对于多重范围的范围请求,响应会在首部字段Content- Type标明 multipart/byteranges 后返回响应报文。

如果服务器端无法响应范围请求,则会返回状态码 200 OK 和完整的实体内容。

2.8 内容协商返回最合适的内容

同一个 Web 网站有可能存在着多份相同内容的页面。比如英语版和中文版的 Web 页面,它们内容上虽相同,但使用的语言却不同。

当浏览器的默认语言为英语或中文,访问相同 URI 的 Web 页面时,则会显示对应的英语版或中文版的 Web 页面。这样的机制称为内容协商(Content Negotiation)。

在这里插入图片描述

内容协商机制是指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准。

包含在请求报文中的某些首部字段(如下)就是判断的基准:

Accept、Accept-Charset、Accept-Encoding、Accept-Language、Content-Language

3 一次完整的HTTP请求

在浏览器的地址栏输入 www.baidu.com ,然后回车:

  1. 域名解析
    1. 浏览器先搜索自身的DNS缓存,看有没有对应该域名的IP地址,这个缓存的时间只有一分钟。(查看浏览器自身缓存:chrome://net-internals/#dns)
    2. 如果在浏览器没有找到缓存或者缓存已经失效,则搜索操作系统自身的DNS缓存。
    3. 如果在操作系统中也没有找到缓存或者缓存已经失效。则读取本地的hosts文件。(Windows的hosts文件地址:C:\WINDOWS\system32\drivers\etc\)
    4. 如果在host文件中找不到对应的配置,浏览器则发起一个DNS的系统调用。主机向本地域名服务器(宽带运营商服务器)发出查询:
      1. 本地域名服务器查看本身缓存。如果本地域名服务器没有该域名的缓存,则发起一个迭代DNS解析的请求。
      2. 本地域名服务器会向根域名服务器发送迭代查询请求报文,查询域名对应的IP地址。如果根域名服务器知道,则给出IP地址;否则,根域名服务器会给出com域的顶级域名服务器的IP地址,让本地域名服务器再向顶级域名服务器查询。
      3. 本地域名服务器向顶级域名服务器发送迭代查询请求报文,查询域名对应的IP地址。如果顶级域名服务器知道,则给出IP地址;否则,顶级域名服务器会给出baidu.com域的权限域名服务器的IP地址,让本地域名服务器再向权限域名服务器查询。
      4. 到了baidu.com域的权限域名服务器(域名注册商的地址,例如万网),拿到www.mshanzi.com对应的IP地址。
      5. 本地域名服务器把结果返回操作系统内核同时缓存起来。
      6. 操作系统内核把结果返回浏览器。
      7. 最后浏览器拿到了baidu.com对应的IP地址。
  2. 浏览器通过域名解析获取域名的IP地址之后,发起TCP连接请求尝试建立连接。主要是三次握手,前面讲过了。
  3. 建立起连接之后,浏览器就可以向服务器发送http请求了,例如请求baidu.com的资源。
  4. 服务器端接受到了这个请求,根据路径参数,经过后端的一些处理之后,把处理后的结果数据返回给浏览器,比如页面完整的html代码、JSON数据等返回给浏览器。
  5. 浏览器如果是拿到了完整的html代码后,在解析和渲染这个页面的时候,里面的JS,CSS,图片静态资源,他们同样也是一个个http请求,都要经过上面的主要4个步骤。
  6. 浏览器根据拿到的资源(如果是JSON数据则对原始页面进行渲染)对页面进行渲染,最终把一个完整的页面呈现给了用户。
  7. 断开TCP连接,主要是四次挥手,前面讲过了。
    1. 根据Connection请求头,如果是keep-alive服务器就保持住tcp连接而不会立即断开连接,如果没有或是close则服务器response传输完后主动关闭tcp连接。当然现在浏览器都是http1.1都默认是keep-alive的,在浏览器tab关闭时,tcp连接关闭。

参考:   《图解HTTP》   w3cHTTP教程

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!