HTTP 协议
HTTP 协议
《图解 HTTP》阅读笔记
HTTP 基础知识
HTTP 协议用于客户端和服务端之间的双向通信,使用 URI 定位互联网上的资源,通过请求报文和响应报文建立通信
HTTP 协议基于 TCP 协议,默认应用端口为80
HTTP/3改用UDP协议
HTTP报文
报文内容
请求报文是由请求方法、请求 URI、协议版本、可选的请求首部字段和内容实体构成的,编码格式为ASCII

响应报文基本上由协议版本、状态码(表示请求成功或失败的数字代码)、用以解释状态码的原因短语、可选的响应首部字段以及实体主体构成

请求报文:
- 报文首部
- 请求行 - 用于请求的方法,请求 URI 和 HTTP 版本
- 请求首部字段 - 从客户端向服务器端发送请求报文时使用的首部,补充了请求的附加内容、客户端信息、响应内容相关优先级等信息
- 通用首部字段 - 请求报文和响应报文两方都会使用的首部
- 实体首部字段 - 针对请求报文和响应报文的实体部分使用的首部,补充了资源内容更新时间等与实体有关的信息
- 其他 - 包含 HTTP 的 RFC 里未定义的其他首部(Cookie 等)
- 空行(CR+LF) - CR:回车符;LF:换行符
- 报文主体(非必需)
响应报文:
- 报文首部
- 状态行 - HTTP 版本,表明响应结果的状态码和原因短语
- 响应首部字段 - 从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。
- 通用首部字段
- 实体首部字段
- 其他
- 空行(CR+LF)
- 报文主体(非必需)
报文(message):HTTP 通信中的基本单位,由8位组字节流(octet sequence,其中 octet 为 8 个比特)组成,通过 HTTP 通信传输。
实体(entity):作为请求或响应的有效载荷数据(补充项)被传输,其内容由实体首部和实体主体组成。
通常,报文主体等于实体主体,传输中进行编码操作时实体主体的内容发生变化
首部字段
HTTP 首部字段格式为 {首部字段名}: {字段值}
首部字段用于给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容。
对单一报文中相同首部字段名重复出现的处理在规范内尚未明确,依赖于浏览器的内部处理逻辑
标准中没有对每个协议头字段的名称和值的大小设置任何限制,也没有限制字段的个数。然而,出于实际场景及安全性的考虑,大部分的服务器、客户端和代理软件都会实施一些限制
HTTP 首部字段根据是否缓存代理分成 2 种类型:
- 端到端首部(End-to-end Header)
- 此类别中的首部会转发给请求 / 响应对应的最终接收目标,且必须保存在由缓存生成的响应中,另外规定它必须被转发。
- 逐跳首部(Hop-by-hop Header)
- 此类别中的首部只对单次转发有效,会因通过缓存或代理而不再转发。HTTP/1.1 和之后版本中,如果要使用 hop-by-hop 首部,需提供 Connection 首部字段。
- HTTP/1.1中的逐跳首部字段:Connection、Keep-Alive、Proxy-Authenticate、Proxy-Authorization、Trailer、TE、Transfer-Encoding、Upgrade
根据实际用途又分为以下4种类型:
- 通用首部字段(General Header Fields) - 请求报文和响应报文两方都会使用的首部
- 请求首部字段(Request Header Fields) - 从客户端向服务器端发送请求报文时使用的首部,补充了请求的附加内容、客户端信息、响应内容相关优先级等信息
- 响应首部字段( Response Header Fields) - 从服务器端向客户端返回响应报文时使用的首部,补充了响应的附加内容,也会要求客户端附加额外的内容信息
- 实体首部字段(Entity Header Fields) - 针对请求报文和响应报文的实体部分使用的首部,补充了资源内容更新时间等与实体有关的信息
常见首部字段
- 通用首部字段
Cache-Control- 控制缓存的行为Connection- 客户端要求服务器使用HTTP 长连接机制Transfer-Encoding- 指定报文主体的传输编码形式
- 请求首部字段
Host- 客户端发送时指定服务端的域名Accept- 客户端可处理的资源类型
- 响应首部字段
Location- 令客户端重定向至指定 URI
- 实体首部字段
Allow- 资源可支持的 HTTP 方法Content-Length- 服务端响应时告知数据长度Content-Type- 服务器响应时告知数据格式Content-Encoding- 服务器响应时告知数据压缩方法
具体的首部字段内容及说明可查阅 HTTP头字段-维基百科
请求报文首部示例:
GET / HTTP/1.1
Host: hackr.jp
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*; q=0.8
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
响应报文首部示例:
HTTP/1.1 200 OK
Date: Fri,13 Jul 2012 02:45:26 GMT
Server: Apache
Last-Modified: Fri,31 Aug 2007 02:02:20 GMT
BTag: "45bae1-16a-46d776ac"
Accept-Ranges: bytes
Content-Length: 362
Connection: close
Content-Type: text/html
Content-Encoding: gzip
HTTP请求方法
常见HTTP方法包括:
| 方法 | 作用 | 协议 |
|---|---|---|
| GET | 从服务器获取指定资源 | 1.0、1.1 |
| POST | 在服务器新建资源 | 1.0、1.1 |
| PUT | 在服务器更新资源(请求方提供完整资源) | 1.0、1.1 |
| DELETE | 从服务器删除资源 | 1.0、1.1 |
| PATCH | 在服务器更新资源(请求方提供改变的属性) | 1.1 |
| HEAD | 获取报文首部字段 | 1.0、1.1 |
| OPTIONS | 询问支持方法 | 1.1 |
| TRACE | 追踪路径 | 1.1 |
| CONNECT | 要求用隧道协议连接代理 | 1.1 |
GET 方法是安全且幂等的,无论操作多少次,服务器上的数据都安全且每次的结果相同
所以浏览器可以对 GET 请求的数据做缓存,而且在浏览器中 GET 请求可以保存为书签
POST 是新增或提交数据的操作,会修改服务器上的资源,所以是不安全且非幂等的
所以浏览器一般不会缓存 POST 请求,也不能把 POST 请求保存为书签
GET,HEAD,PUT 和 DELETE 方法都有幂等属性,同样由于根据协议,OPTIONS,TRACE 都不应有副作用,因此也理所当然也是幂等的
GET 请求可以携带 body ,RFC 规范定义的 GET 请求是获取资源,所以根据这个语义不需要用到 body
HTTP 的 GET 请求不一定具有幂等性,在实际应用中,GET 请求通常用于获取资源的操作,例如读取文章、获取用户信息等。如果 GET 请求只是获取资源,不对资源状态做出修改,则可以确保具有幂等性。也就是说,多次发起相同的 GET 请求,得到的响应结果应该是相同的
但是,如果 GET 请求携带了一些参数,比如在 URL 中添加了时间戳或随机数等不同的标识符,那么每次请求得到的结果可能不同,因此 GET 请求就不具有幂等性
此外,一些 web 应用程序可能会在 GET 请求中使用类似于购买商品或者转帐等修改资源状态的操作,这样的 GET 请求就不具有幂等性,因为相同的请求可能会对资源状态做出不同的修改
总之,GET 请求是否具有幂等性取决于具体的场景和实现。在编写 web 应用程序时,需要根据具体的需求和场景来确定请求的幂等性。
数据传输
需传输的数据编码压缩后,分块传输,由客户端进行解码恢复
- 常见内容编码包括:
- gzip(GNU zip)
- compress(UNIX 系统的标准压缩)
- deflate(zlib)
- identity(不进行编码)
- 块使用十六进制标记大小,实体主体的最后一块会使用“0(CR+LF)”来标记
对于包含多种数据类型的实体,采用多部分对象集合并在首部字段中加入Content-type
- 多部分对象集合的每个部分类型中,都可以含有首部字段
- 可以在某个部分中嵌套使用多部分对象集合
对于断连后的重新传输,可以通过范围请求指定下载的实体范围,仅请求部分资源,请求报文首部字段包含Range
HTTP 缓存
可将一些具有重复性的 HTTP 请求及其响应缓存在本地以提升性能
强制缓存
强制缓存指只要浏览器判断缓存没有过期,则直接使用本地缓存
强制缓存利用 HTTP 首部字段中的 Cache-Control (相对时间)和 Expires (绝对时间)字段实现,它们都用来表示资源在客户端缓存的有效期:
如果 HTTP 响应头部同时有 Cache-Control 和 Expires 字段的话,Cache-Control 的优先级高于 Expires
Cache-control 选项更多一些,设置更加精细,所以建议使用 Cache-Control 来实现强制缓存
具体的实现流程如下:
- 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在响应报文头部加上
Cache-Control设置过期时间大小 - 浏览器再次请求访问服务器中的该资源时,先通过请求资源的时间与
Cache-Control中设置的过期时间大小计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器 - 服务器再次收到请求后,通过响应报文再次更新
Cache-Control
协商缓存
协商缓存指客户端与服务端协商之后,通过协商结果来判断是否使用本地缓存
协商缓存的响应报文状态码为304,有两种实现方式
- 通过请求头部中的
If-Modified-Since字段与响应头部中的Last-Modified字段实现Last-Modified:标示这个响应资源的最后修改时间If-Modified-Since:当资源过期时,浏览器发现响应头中有Last-Modified声明,则再次发起请求的时候使用If-Modified-Since告知服务器Last-Modified值,服务器将其与被请求资源的最后修改时间进行对比- 如果最后修改时间较新(大),说明资源又被改过,则返回最新资源,HTTP 200 OK
- 如果最后修改时间较旧(小),说明资源无新修改,响应 HTTP 304 走缓存
- 通过请求头部中的
If-None-Match字段与响应头部中的ETag字段实现Etag:唯一标识响应资源If-None-Match:当资源过期时,浏览器发现响应头里有Etag,则再次发起请求时使用If-None-Match告知服务器Etag值,服务器收到请求后进行比对,如果资源没有变化返回 304,如果资源变化了返回 200
相较于 Last-Modified,ETag 有如下优势:
- 可以更加准确地判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题
- 可能有些文件是在秒级以内修改的,
If-Modified-Since能检查到的粒度是秒级的,使用 Etag就能够保证这种需求下客户端在 1 秒内能刷新多次 - 有些服务器不能精确获取文件的最后修改时间
协商缓存需要配合强制缓存中 Cache-Control 字段使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求
状态管理
HTTP 协议为无状态协议,不对之前发生过的请求和响应的状态进行管理,需使用Cookies记录状态
Cookies
客户端和服务端首次通信时,服务器端通过响应报文内的 Set-Cookie 的首部字段信息(格式为 key=value)通知客户端保存服务器发送的 Cookie
下次客户端向该服务器发送请求时自动在请求报文中加入 Cookie 值后发送,服务端检查 Cookie 获取状态信息
服务器有时会在响应头里添加多个 Set-Cookie,但客户端发送时不需要用多个 Cookie 字段,只要在一行里用 ; 隔开就行
由于 Cookie 通常记录客户的关键识别信息,需要使用属性来保护,防止外泄或窃取
- 有效期
Expires- 失效的绝对时间Max-Age- 优先采用,失效的相对时间
- 作用域
Domain- 指定 Cookie 所属的域名Path- 指定 Cookie 所属的路径
- 安全性
HttpOnly- 告诉浏览器此 Cookie 只能通过浏览器 HTTP 协议传输,禁止其他方式访问SameSite- 防范跨站请求伪造(XSRF)攻击,SameSite=Strict可以严格限定 Cookie 不能随着跳转链接跨站发送,而SameSite=Lax允许 GET/HEAD 等安全方法,但禁止 POST 跨站发送Secure- 表示这个 Cookie 仅能用 HTTPS 协议加密传输,明文的 HTTP 协议会禁止发送,但 Cookie 本身不是加密的,浏览器里还是以明文的形式存在
Cookie 应用:
- 身份识别 - 最基本的用途,保存用户的登录信息,实现会话事务
- 广告跟踪 - 广告商网站(例如 Google)为用户设置 Cookie 以使广告用 Cookie 读出用户身份推出定制广告,这种 Cookie 不是由访问的主站存储的,所以又叫第三方 Cookie(third-party cookie)
Session
如果说 Cookie 是客户端行为,那么 Session 就是服务端行为
Cookie 机制在最初和服务端完成交互后,保持状态所需的信息都将存储在客户端,后续直接读取发送给服务端进行交互
Session 代表服务器与浏览器的一次会话过程,将用户的所有活动信息、上下文信息、登录信息等都存储在服务端,只是生成一个唯一标识 ID 发送给客户端,后续的交互将没有重复的用户信息传输,取而代之的是唯一标识 ID
- 当客户端第一次请求 session 对象时候,服务器会为客户端创建一个 session,并将通过特殊算法算出一个 session 的 ID,用来标识该 session 对象
- 当浏览器下次请求别的资源的时候,浏览器会将 sessionID 放置到请求头中,服务器接收到请求后解析得到 sessionID,服务器找到该 id 的 session 来确定请求方的身份和一些上下文信息
session 的实现方式包括 Cookie 和 url 重写
cookie 为首选方式,url 重写则在禁止 cookie 的情况下提供服务,将会话标识号以参数形式附加在超链接的 URL 地址后面的技术称为 URL 重写
问题:
- Session 信息存储在服务端占用空间,因此如果用户量很大的场景,Session 信息占用的空间不容忽视
- 对于集群化&分布式的服务器配置,需要引入高可用的 Session 集群方案,引入 Session 代理实现信息共享,或者实现定制化哈希使用户负载均衡后始终访问同一节点
Token - JWT
Token 是由服务端生成并发放给客户端,具有时效性的一种验证身份的手段
原理是服务器认证以后生成一个 JSON 对象发回给用户,之后用户与服务端通信的时候,都发回这个 JSON 对象,服务器完全依赖该对象认定用户身份
- 客户端将用户的账号和密码提交给服务器
- 服务器对其进行校验,通过则生成一个 token 值,将其保存在数据库,同时也返回给客户端,作为后续的请求交互身份令牌
- 客户端拿到服务端返回的 token 值后,可将其保存在本地,以后每次请求服务器时都携带该 token,提交给服务器进行身份校验
- 服务器接收到请求后,解析出其中的 token,再根据相同的加密算法和参数生成 token 与客户端的 token 进行对比,一致则通过,否则拒绝服务
- token 验证通过,服务端就可以根据该 token 中的 uid 获取对应的用户信息,进行业务请求的响应
优势
- 无状态 - token 自身包含了身份验证所需要的所有信息,使得服务器不需要存储 Session 信息,减轻了服务端的压力
- 防止 CSRF 攻击 - CSRF (跨站请求伪造)源于 Cookie + Session 的鉴权方式中,鉴权数据由浏览器自动携带发送到服务端的,借助这个特性,攻击者就可以通过让用户误点攻击链接,达到攻击效果,而 token 是通过客户端本身逻辑作为动态参数加到请求中的,token 也不会轻易泄露出去,因此 token 在 CSRF 防御方面存在天然优势
- 适合移动应用 - 移动端上不支持 cookie,而 token 只要客户端能够进行存储就能够使用,因此 token 在移动端上也具有优势
劣势
- 无状态问题 - 当后端在 token 有效期内用户 Logout 或者更改它的权限的话,不会立即生效,如果没有增加额外的处理逻辑,则一般需要等到有效期过后才可以
- 性能问题 - Token 以时间换空间
Token 设计
以 JSON Web Token(JWT)为例,Token 主要由 3 部分组成:
- Header 头部信息 - 记录了使用的加密算法信息
- Payload 净荷信息 - 记录了用户信息和过期时间等
- Signature 签名信息 - 对前两部分的签名,防止数据篡改
服务器生成的 JWT token 的形式为 Header.Payload.Signature,其中 header 和 payload 的信息不做加密,只做一般的 base64URL 编码,signature 使用 header 里指定的签名算法外加服务器密钥加密生成
之后服务端每次收到 token 后剥离出 header 和 payload 获取算法、用户、过期时间等信息,然后根据自己的密钥生成 signature,并与 token的 signature 进行一致性验证,实现用 CPU 加解密的时间换取存储空间
JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分
JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限,也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑
JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限,为了减少盗用,JWT 的有效期应该设置得比较短,对于一些比较重要的权限,使用时应该再次对用户进行认证
为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输
返回内容
服务器存在多个相同内容的页面时,通过内容协商机制返回合适内容
内容协商机制指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。
内容协商以响应资源的语言、字符集、编码方式等作为判断的基准。
机制类型:
- 服务器驱动协商(Server-driven Negotiation)
- 由服务器端进行内容协商。以请求的首部字段为参考,在服务器端自动处理
- 透明协商(Transparent Negotiation)
- 是服务器驱动和客户端驱动的结合体,是由服务器端和客户端各自进行内容协商的一种方法
- 客户端驱动协商(Agent-driven Negotiation)
- 由客户端进行内容协商的方式。用户从浏览器显示的可选项列表中手动选择
跨域
跨域指的是不同源之间的资源访问,当一个请求 url 的协议、域名、端口三者之间的任意一个与当前页面 url 不同即为跨域
只要请求的 url 有以下不同,都属于“跨域”:
- 协议: http, https, …
- 域名
- 端口
产生原因
在前后端分离的模式下,前后端的域名是不一致的,此时就会发生跨域访问问题
浏览器的同源策略限制会阻止一个域的 js 脚本和另外一个域的内容进行交互,如果缺少同源策略,浏览器很容易受到 XSS、CSFR 等攻击
所谓同源(即在同一个域)就是两个页面具有相同的协议(protocol)、主机(host)和端口号(port)
非同源会出现的限制
- 无法读取非同源网页的 cookie、localstorage 等
- 无法接触非同源网页的 DOM 和 js 对象
- 无法向非同源地址发送 Ajax 请求
解决方法
nginx 反向代理
正向代理:a-->b 访问不了,可以使用中间服务器 c, 先访问 c 再从 c 到 b,访问的目的地明确,但是用户不知道中间的代理服务器 (忽略代理服务器)
反向代理:a--> c <--b,a 明确访问 c 代理服务器,但是不知道 c 的内容从哪里来,c 反向从别的地方拿来数据 (忽略目标地址)
CORS 解决跨域(添加响应头)
浏览器先询问 b,b 允许 a 访问
CORS 机制通过允许服务器标示除了它自己以外的其他域,使得浏览器允许这些域访问加载自己的资源
浏览器将 CORS 请求分为简单请求和非简单请求
简单请求会在发送时自动在 HTTP 请求头加上 Origin 字段,来标明当前是哪个源(协议+域名+端口),服务端来决定是否放行
非简单请求则会先发一个 OPTIONS 预检请求给服务端,当通过了再发正常的 CORS 请求
CORS 标准新增了一组 HTTP 标头字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源
规范要求对那些可能对服务器数据产生副作用的 HTTP 请求方法,浏览器必须首先使用 OPTIONS 方法发起一个预检请求,从而获知服务端是否允许该跨源请求,服务器确认允许之后,才发起实际的 HTTP 请求
在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(例如 Cookie 和 HTTP 认证相关数据)
通过 jsonp 解决跨域(老方法)
通常为了减轻web服务器的负载把js、css、图片等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许。
html 中有的标签天然支持跨域,比如 <script src="http://www.baidu.com"></script>,但是只支持 get 请求
用户身份认证
常见认证信息:密码、动态令牌、数字证书、生物认证、IC卡等
HTTP/1.1使用的认证方式:BASIC 认证(基本认证)、DIGEST 认证(摘要认证)、SSL 客户端认证、FormBase 认证(基于表单认证)等
Basic 认证

- 安全性低,明文解码后就是用户 ID和密码
- 一般浏览器无法实现认证的注销操作
DIGEST认证

- ①中首部字段
WWW-Authenticate内必须包含realm和nonce这两个字段的信息。客户端就是依靠向服务器回送这两个值进行认证的。 - ②中首部字段
Authorization内必须包含username、realm、nonce、uri和response的字段信息。realm和nonce就是之前从服务器接收到的响应中的字段。username是realm限定范围内可进行认证的用户名uri(digest-uri)即Request-URI的值,经代理转发后Request-URI的值可能被修改,因此事先会复制一份副本保存在uri内。response也可叫做Request-Digest,存放经过 MD5 运算后的密码字符串,形成响应码。
SSL客户端认证
借由 HTTPS 的客户端证书完成认证
步骤:
- 接收到需要认证资源的请求,服务器会发送
CertificateRequest报文,要求客户端提供客户端证书。 - 用户选择将发送的客户端证书后,客户端会把客户端证书信息以
Client Certificate报文方式发送给服务器。 - 服务器验证客户端证书验证通过后方可领取证书内客户端的公开密钥,然后开始 HTTPS 加密通信。
多数情况下和表单认证组合形成一种双因素认证(Two-factor authentication)来使用
表单认证
基于表单的认证方法不是在 HTTP 协议中定义的,客户端会向服务器上的 Web 应用程序发送登录信息(Credential),按登录信息的验证结果认证。
用户身份认证多半基于表单认证
基于表单认证的标准规范尚未有定论,一般会使用 Cookie 来管理 Session(会话)
- 客户端使用HTTPS进行用户输入数据(用户名&密码)的发送
- 服务器将用户认证状态和Session ID绑定后向用户发放包含Session ID的cookies
- 之后客户端发送请求时服务器验证接收到的Cookies中的Session ID识别用户和其认证状态
服务器端应如何保存用户提交的密码等登录信息等也没有标准化,通常的安全做法是先利用给密码加盐(salt)的方式增加额外信息,再使用散列(hash)函数计算出散列值后保存。
- salt 是由服务器随机生成的一个长度足够长的字符串,和密码字符串相连接(前后都可以)生成散列值。
- 当两个用户使用了同一个密码时,由于随机生成的 salt 值不同,对应的散列值也将是不同的。
Web 服务器
虚拟主机
HTTP/1.1 规范允许一台 HTTP 服务器搭建多个 Web 站点,因此利用虚拟主机可令一个IP地址配对多个URI
互联网通过DNS服务将URI解析为IP进行连接,连接至服务器上通过首部中的Host指定的URI确认具体的访问域名
转发服务器
代理/缓存
代理服务器(proxy server)也叫Web缓存器(Web cache),其接收客户端发送的请求后转发给其他服务器。代理不改变请求 URI,会直接发送给前方持有资源的目标服务器。
每次通过代理服务器转发请求或响应时,会追加写入Via首部信息
用途:利用缓存技术减少网络带宽的流量,组织内部针对特定网站的访问控制,以获取访问日志为主要目的等等
类型:缓存/非缓存代理、透明/非透明代理
代理转发响应时,缓存代理(Caching Proxy)会预先将资源的副本(缓存)保存在代理服务器上
转发请求或响应时,不对报文做任何加工的代理类型被称为透明代理
缓存服务器是代理服务器的一种,并归类在缓存代理类型中,缓存可以存在于缓存服务器内或客户端浏览器中。判定缓存过期后,会向源服务器确认资源的有效性,若判断浏览器缓存失效,浏览器会再次请求新资源。缓存服务器既是服务器又是客户端。 当它接收浏览器的请求并发回响应时是服务器。当它向初始服务器发出请求并接收响应时是客户端。
- 降低客户端响应时间
- 减轻服务器负载
对于缓存的版本问题,HTTP使用条件GET(conditional GET)方法,在GET方法的首部字段中加入If-Modified-Since字段以确认缓存文件是否改变
网关
转发其他服务器通信数据的服务器
用途:可以由 HTTP 请求转化为其他协议通信
隧道
在相隔甚远的客户端和服务器两者之间进行中转,并保持双方通信连接的应用程序
用途:用 SSL 等加密手段进行通信,确保客户端能与服务器进行安全的通信


