本文共 4913 字,大约阅读时间需要 16 分钟。
HTTP/2在2015年已推出,本文主要介绍的是HTTP1.1。下面是RFC2616对HTTP1.1的描述:
The Hypertext Transfer Protocol (HTTP) is an application-level protocol for distributed, collaborative, hypermedia information systems. It is a generic, stateless, protocol which can be used for many tasks beyond its use for hypertext, such as name servers and distributed object management systems, through extension of its request methods, error codes and headers.
HTTP1.1 作为一个应用层协议,有如下的一些特点:
当前大部分网站都已经切换到HTTPS, 并且Chrome 68正式版会把所有潜在不安全的HTTP网站标记为不安全。HTTPS是在HTTP下加入SSL/TLS安全层,增强了网络访问的安全性。TLS(Transport Layer Security)是SSL的v3.0升级版,已经是HTTPS的标准。HTTP和HTTPS有如下的区别:
一个典型交互场景如下:
学习网络协议细节时,一个很重要的手段就是看RFC(Request For Comments),基本的互联网通信协议都有在RFC里详细说明。下面是HTTP的RFC:
HTTP访问从URL开始,Uniform Resource Locator (URL)的格式为:
protocol://hostname:port/path-and-file-name# port: server监听的TCP port,http缺省是80# path-and-file-name: server的文件路径
在浏览器输入URL,浏览器会发起一个http request,使用Chrome或者Firefox开发者工具的Network选项可以查看HTTP请求与响应头内容。
HTTP的报文结构如下图,左右分别是请求和响应报文的结构:
详细说明可以看RFC的对应章节。Request Line
的标准格式为: # request linerequest-method-name request-URI HTTP-version# method举例: GET, POST# request-URI: 指定请求的资源# HTTP-version: HTTP/1.0 or HTTP/1.1
当request消息到达server时,服务器会做以下处理中的一项:
Status Line
的标准格式为: # Status LineHTTP-version status-code reason-phrase# HTTP-version: HTTP/1.0 or HTTP/1.1# status-code: 三位数字的返回码, 如: 200 ok, 403 Forbidden, 404 Not Found# reason-phrase: 返回码的简短解释
然后client(通常就是浏览器)收到server的response消息,会把内容显示在页面,浏览器会渲染HTML并执行JS.
每个 http request 请求都可以携带一个方法,最常见的就是 GET 和 POST,还有其他方法这里不做介绍,可以看RFC。
GET request-URI HTTP-version(optional request headers)(optional request body)
请求header里如果携带了 Connection: Keep-Alive
,那么要求server不要马上关闭TCP连接。HTTP/1.1 默认指定 keep-alive,可以提高网络效率。并且 HTTP/1.1 server支持虚拟主机,即同一个host有不同的hostname,不同host有各自指定的不同的根目录,因此 HTTP/1.1 默认要求request header指定host字段。
URL无法携带特殊字符,遇到特殊字符用%xx
编码,xx是ASCII hex coe,如空格可被编码为 %20
或+
.
GET 携带查询参数, 是在URL里传参的,比如如下form制定GET方法提交
点击提交,浏览器生成的request消息如下:
GET /bin/login?user=Peter+Lee&pw=123456&action=login HTTP/1.1Accept: image/gif, image/jpeg, */*Referer: http://127.0.0.1:8000/login.htmlAccept-Language: en-usAccept-Encoding: gzip, deflateUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)Host: 127.0.0.1:8000Connection: Keep-Alive
上面request line的URI传参:?user=Peter+Lee&pw=123456&action=login
,然后server可以解析这个字符串获取对应的参数。
POST方法可以post额外的数据到server,如提交表单或上传文件,一个POST请求如下:
POST request-URI HTTP-versionContent-Type: mime-typeContent-Length: number-of-bytes(other optional request headers)(URL-encoded query string)
对于POST, request header 里的Content-Type
和 Content-Length is necessary
是必选字段,指定post数据的类型和长度。
提交表单,产生如下的http request请求
POST /bin/login HTTP/1.1Host: 127.0.0.1:8000Accept: image/gif, image/jpeg, */*Referer: http://127.0.0.1:8000/login.htmlAccept-Language: en-usContent-Type: application/x-www-form-urlencoded # type, post必选字段Accept-Encoding: gzip, deflateUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)Content-Length: 37 # length, post必选字段, 下面post数据37个字符Connection: Keep-AliveCache-Control: no-cacheUser=Peter+Lee&pw=123456&action=login
POST request提交的数据没有大小限制,并且不会再浏览器地址栏显示,适合敏感或大量数据提交。对于上面里子,post携带的参数就是最后的 User=Peter+Lee&pw=123456&action=login
, server 解析这个字符串即可获取对应数据。
如使用curl查看一次http的请求响应,内容如下:
root@ubuntu:~# curl -v www.baidu.com* Rebuilt URL to: www.baidu.com/* Hostname was NOT found in DNS cache* Trying 115.239.211.112...* Connected to www.baidu.com (115.239.211.112) port 80 (#0)> GET / HTTP/1.1> User-Agent: curl/7.35.0> Host: www.baidu.com> Accept: */*>< HTTP/1.1 200 OK< Accept-Ranges: bytes< Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform< Connection: Keep-Alive< Content-Length: 2381< Content-Type: text/html< Date: Sun, 26 Aug 2018 05:40:50 GMT< Etag: "58860504-94d"< Last-Modified: Mon, 23 Jan 2017 13:28:36 GMT< Pragma: no-cache* Server bfe/1.0.8.18 is not blacklisted< Server: bfe/1.0.8.18< Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/<......
可以看这篇:。