客户端和服务端通过交换各自的消息(与数据流正好相反)进行交互。由像浏览器这样的客户端发出的消息叫做 requests,被服务端回应的消息叫做 responses。
常见的中介有:代理(Proxy)、网关(gateway)、通道(tunnel)。
代理:根据URI的绝对格式来接收请求,重写全部或部分消息,通过URI的表示把已格式化的请求发送给服务器。代理既可以表现得透明,又可以不透明(相对于应用层来说)。代理主要有如下几种作用:
- 缓存(可以是公开的也可以是私有的,像浏览器的缓存)
- 过滤(像反病毒扫描,家长控制...)
- 负载均衡(让多个服务器服务不同的请求)
- 认证(对不同资源进行权限管理)
- 日志记录(允许存储历史信息)
网关:一种接收代理,作为一些其他服务器的上层,并且如果必须的话,把请求翻译给下层的服务器协议。
通道:不改变消息的两个连接之间的中继点。
HTTP是一个client-server协议:请求通过一个实体被发出,实体也就是用户代理。大多数情况下,这个用户代理都是指浏览器。
user-agent 就是任何能够为用户发起行为的工具。这个角色通常都是由浏览器来扮演。一些例外情况,比如是工程师使用的程序,以及Web开发人员调试应用程序。要展现一个网页,浏览器首先发送一个请求来获取页面的HTML文档,再解析文档中的资源信息发送其他请求,获取可执行脚本或CSS样式来进行页面布局渲染,以及一些其它页面资源(如图片和视频等)。然后,浏览器将这些资源整合到一起,展现出一个完整的文档,也就是网页。浏览器执行的脚本可以在之后的阶段获取更多资源,并相应地更新网页。
关于HTTP是”无状态,有会话的”:
HTTP是无状态的:在同一个连接中,两个执行成功的请求之间是没有关系的。这就带来了一个问题,用户没有办法在同一个网站中进行连续的交互,比如在一个电商网站里,用户把某个商品加入到购物车,切换一个页面后再次添加了商品,这两次添加商品的请求之间没有关联,浏览器无法知道用户最终选择了哪些商品。而使用HTTP的头部扩展,HTTP Cookies就可以解决这个问题。把Cookies添加到头部中,创建一个会话让每次请求都能共享相同的上下文信息,达成相同的状态。
HTTP流的建立:
1.打开一个TCP连接:客户端可能打开一条新的连接,或重用一个已经存在的连接,或者也可能开几个新的TCP连接连向服务端。
2.发送一个HTTP报文(HTTP/2前语义可读,其后被封装在帧中,不能被直接读取)
以HTTP/1.1为例,形如:
GET / HTTP/1.1
Host: developer.mozilla.org
Accept-Language: fr
3.读取服务器端返回的报文信息:
HTTP/1.1 200 OK
Date: Sat, 09 Oct 2010 14:28:02 GMT
Server: Apache
Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT
ETag: "51142bc1-7449-479b075b2891b"
Accept-Ranges: bytes
Content-Length: 29769
Content-Type: text/html
<!DOCTYPE html... (here comes the 29769 bytes of the requested web page)
4.关闭连接或为后续请求重用连接
HTTP/1.0报文类型:请求和响应
请求报文格式:
request-line(起始行:request-method ruquest-URL HTTP版本号)
headers(0个或多个)
<blank line>
body(仅当POST请求有效)
其中,request-method 经常是由一个动词像GET,POST或者一个名词像OPTIONS,HEAD来定义客户端的动作行为。通常客户端的操作都是获取资源(GET方法)或者发送HTML表单值(POST方法)。
响应报文格式:
status-line(起始行)
headers(0个或多个)
<blank line>
body(可选消息体)
其中,status-line格式通常为:HTTP版本号 response-code(服务器响应码) response-phrase构成
起始行和 HTTP 消息中的HTTP 头统称为请求头,而其有效负载被称为消息正文。
常见的headers类型为一般头、请求头,响应头,实体头(用于描述主题,可以出现在POST请求和所有响应报文中)
创建cookie时,服务器使用set-cookie响应头部告知客户端保存cookie信息,其中:
会话期cookie的创建:
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry
持久性cookie的创建:
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
当cookie被创建后,服务器再次发送新请求时,会利用cookie头部发送给服务器:
GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
cookie的作用域有Domain和Path指定,默认为当前主机
Content-Type实体头部用于指示资源的MIME类型,在响应中,Content-Type标头告诉客户端实际返回的内容的内容类型。浏览器会在某些情况下进行MIME查找,并不一定遵循此标题的值; 为了防止这种行为,可以将标题 X-Content-Type-Options
设置为 nosniff。 指令:
media-type
资源或数据的 MIME type 。
charset
字符编码标准。
boundary
对于多部分实体,boundary 是必需的,其包括来自一组字符的1到70个字符,已知通过电子邮件网关是非常健壮的,而不是以空白结尾。它用于封装消息的多个部分的边界。
例如:
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