HTTP(Hypertext Transfer Protocol)就是超文本传输协议,它是现代互联网最重要也是最基本的协议。Http协议是无状态的、应用层协议,它是web开发的基础,如果想从事web方面的开发,一定要仔细学习一下这个协议。
一、Http基础
Http设计的目的就是支持客户端(一般是浏览器)和服务器端进行方便的沟通,它是一个B/S协议。因为在互联网中,一个服务器往往需要处理大量的客户端请求,Http协议应该尽可能少的占用系统资源。 为了达到这个目的,Http协议被设计成无状态的。Http协议是在TCP/IP之上的一种协议(Http属于应用层,TCP/IP属于运输层),默认端口采用的是80。
Http协议栈:
我们把Http协议中通信的两方称作Client和Server(或Host),Client向Server端经过http协议发送一个Request,Server端收到Request后经过一些列的处理返回Client一个Response,整个过程如下图所示:
我们现在用到的版本是HTTP/1.1,它比1.0版本添加了更多特性。其中比较重要的特性有:
* 支持持久连接
* 支持消息切分成块传输
* 更加丰富的cache特性
* 带宽优化及网络连接的使用
* 错误通知的管理
* 互联网地址的维护安全性及完整性
二、URL
在详细介绍Http协议之前我们先看一下URL。对于URL我想大家都已经很熟悉了,我们如果访问一个网站,我们不需要了解Http协议,我们只需要在浏览器中输入这个网站的URL即可。Web传输的核心就是请求消息,而请求消息就是通过URL进行定义的。 URL(Uniform Resource Locator) 地址用于描述一个网络上的资源,基本格式如下:
schema://host[:port#]/path/.../[;url-params][?query-string][#anchor]
- scheme:指定低层使用的协议,一般是http,如果强调安全的话可以是http
- host:HTTP服务器的IP地址或者域名
- port:HTTP服务器的默认端口是
80
,这种情况下端口号可以省略。如果使用了别的端口,必须指明 - path:访问资源的路径
- url-params:URL的参数
- query-string:发送给http服务器的数据
- anchor:锚
2.1 URL 的一个例子
http://www.mywebsite.com/sj/test;id=8079?name=sviergn&x=true#stuff
Schema: http
host: www.mywebsite.com
path: /sj/test
URL params: id=8079
Query String: name=sviergn&x=true
Anchor: stuffif x:
print('True')
2.2 一个URL的请求过程:
当你在浏览器输入URLhttp://www.website.com
的时候,浏览器发送一个Request去获取http://www.website.com
的html。服务器把Response发送回给浏览器。浏览器分析Response中的 HTML,发现其中引用了很多其他文件,比如图片,CSS文件,JS文件。
浏览器会自动再次发送Request去获取图片,CSS文件,或者JS文件。当所有的文件都下载成功后, 网页就被显示出来了。
三、请求Method(Verb)
我们通过URL告诉了浏览器我们去哪个网站(主机)获得资源,而我们要在这个网站上做什么操作呢?这个具体的操作就是由请求Method定义的。当然,客户端可以对服务器做多种类型的操作,为此Http1.1
协议共定义了八种标准操作:
- GET:向指定的资源发出“显示”请求。使用GET方法应该只用在读取数据,而不应当被用于产生“副作用”的操作中,例如在Web Application中。其中一个原因是GET可能会被网络蜘蛛等随意访问。
- POST:向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)。数据被包含在请求本文中。这个请求可能会创建新的资源或修改现有资源,或二者皆有。
- PUT:向指定资源位置上传其最新内容。
- DELETE:请求服务器删除Request-URI所标识的资源。
- OPTIONS:这个方法可使服务器传回该资源所支持的所有HTTP请求方法。用’*’来代替资源名称,向Web服务器发送OPTIONS请求,可以测试服务器功能是否正常运作。
- HEAD:与GET方法一样,都是向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分。它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中“关于该资源的信息”(元信息或称元数据)。
- TRACE:回显服务器收到的请求,主要用于测试或诊断。
- CONNECT:
HTTP/1.1
协议中预留给能够将连接改为渠道方式的代理服务器。通常用于SSL加密服务器的链接(经由非加密的HTTP代理服务器)。
Method名称是区分大小写的。当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码405(Method Not Allowed)
,当服务器不认识或者不支持对应的请求方法的时候,应当返回状态码501(Not Implemented)
。
其中的GET、POST、PUT、DELETE这四种Method分别对应者对远程服务资源的增、删、改、查操作,而其中最长用的是GET和POST。
3.1 关于GET和POST
GET请求的数据会附在URL之后(就是据放置在HTTP协议头中),以“?”分割URL输数据,多个参数用“&”连接;例如:login.action?name=tom&password=securiy
。
POST会把提交的数据放置在是HTTP包的正文中。上文示例中name=Professional&id=11101
就是实际的传输数据;
HTTP协议没有对传输的数据和URL长度进行限制, 但特定浏览器和服务器对URL长度有限制, 因此对于GET提交时,传输数据就会受到URL长度的限制; 由于POST操作不是通过URL传值,理论上数据长度不受限。
POST的安全性要比GET的安全性高,通过GET提交数据,用户名和密码将明文出现在URL上,容易被他人看到,URL信息也可能会被记录到历史纪录中。
GET实例:
GET /test/?id=11101&name=Professional HTTP/1.1
Host: www.test.com
User-Agent: Mozilla/5.0 (Windows; U;) Firefox/1.0.1
Connection: Keep-Alive
POST 实例:
POST / HTTP/1.1
Host: www.test.com
User-Agent: Mozilla/5.0 (Windows; U) Firefox/1.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
Connection: Keep-Alive
(…… 此处空一行 ……)
name=Professional&id=11101
四、状态码Status Code
通过URL和Method,客户端就可以发送一个完整的请求给服务端。当然服务端也会做出响应。状态码就是非常重要的一种响应,客户端通过状态码就可以了解服务端做出何种响应。HTTP/1.1
中定义了5类状态码, 状态码由三位数字组成,第一个数字定义了响应的类别:
- 1XX 提示信息; 表示请求已被成功接收,告诉客户端可以继续发送下一个请求了,若如果已发送完毕可以忽略它。
- 2XX 成功
- 3XX 重定向; 要完成请求必须进行更进一步的处理
- 4XX 客户端错误;请求有语法错误或请求无法实现
- 5XX 服务器端错误;服务器未能实现合法的请求
4.1 一些常见的状态码
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
最常见的Response处理成功之后返回的状态码:
HTTP/1.1 200 OK (CRLF)
五、Http消息结构
5.1 Http消息结构概览
至此,我们已经了解到了URL、Verb、Status Code相关概念,而这些信息就是组成Http消息体的主要信息,下面我们就具体看一下Http消息体的具体结构。
HTTP消息分为Request和Response两种消息,Http协议对这两种消息定义了如下结构:
message = <start-line>
*(<message-header>)
CRLF
[<message-body>]
<start-line> = Request-Line | Status-Line
<message-header> = Field-Name ':' Field-Value
从上面定义我们可以看到,Http的Request和Response消息都是由三部分组成:
1. start-line 开始行
2. header 消息头
3. body 消息体
对于start-line,又分为:
1. Request-Line : 'METHOD/path-to-resource http-version'
2. Response-Line : 'http-version status-code message'
对于Headers则有如下几种:
1. general headers
2. entity headers
3. request or response headers
a. request specific headers.
b. response specific headers.
下面我们再用两幅图具体看一下Request和Response的消息格式:
Request消息格式定义:
Response消息格式定义:
5.2 Http Headers
通过上面介绍我们已经Http消息的Headers共分为三种,分别是General Headers
、Entity Headers
、Request/Response Headers
。
5.2.1 General Headers
我把被Request和Response共享的Headers成为General Headers,具体有:
general-header = Cache-Control
| Connection
| Date
| Pragma
| Trailer
| Transfer-Encoding
| Upgrade
| Via
| Warning
- Cache -Control指定请求和响应遵循的缓存机制。
- Connection 允许客户端和服务器指定与请求/响应连接有关的选项
- Date 提供日期和时间标志,说明报文是什么时间创建的
- Pragma头域用来包含实现特定的指令,最常用的是Pragma:no-cache
- Trailer 如果报文采用了分块传输编码(chunked transfer encoding) 方式,就可以用这个首部列出位于报文拖挂(trailer)部分的首部集合
- Transfer-Encoding 告知接收端为了保证报文的可靠传输,对报文采用了什么编码方式
- Upgrade 给出了发送端可能想要”升级”使用的新版本和协议
- Via 显示了报文经过的中间节点(代理,网嘎un)
5.2.2 Entity Headers
EntityHeaders主要用来描述消息体(message body)的一些元信息,具体有:
entity-header = Allow
| Content-Encoding
| Content-Language
| Content-Length
| Content-Location
| Content-MD5
| Content-Range
| Content-Type
| Expires
| Last-Modified
其中,以Content为前缀的Headers主要描述了消息体的结构、大小、编码等信息,Expires描述了Entity的过期时间,Last-Modified描述了消息的最后修改时间。
5.2.3 Request/Response Headers
这部分内容放在下面的Request消息体和Response消息体中介绍。
5.3 Request消息体
通过上面介绍,我们对Request消息体结构已经有了大体了解,本节我们再深入介绍一下。
5.3.1 Request-Line
Request-Line是Request消息体的第一部分,其具体定义如下:
Request-Line = Method SP URI SP HTTP-Version CRLF
Method = "OPTIONS"
| "HEAD"
| "GET"
| "POST"
| "PUT"
| "DELETE"
| "TRACE"
其中sp
代码字段的分隔符,HTTP-Version
一般就是"http/1.1"
,后面紧接着是一个换行
。
5.3.2 Request Headers
在Request-Line
后面紧跟着的就是Headers
。我们在上面已经介绍了General Headers
和Entity Headers
,下面便是Request Headers
定义:
request-header = Accept
| Accept-Charset
| Accept-Encoding
| Accept-Language
| Authorization
| Expect
| From
| Host
| If-Match
| If-Modified-Since
| If-None-Match
| If-Range
| If-Unmodified-Since
| Max-Forwards
| Proxy-Authorization
| Range
| Referer
| TE
| User-Agent
Request Headers
扮演的角色其实就是一个Request消息的调节器。需要注意的是若一个headers名称不在上面列表中,则默认当做Entity Headers
的字段。
前缀为Accept
的headers定义了客户端可以接受的媒介类型、语言和字符集等。From
, Host
, Referer
和User-Agent
详细定义了客户端如何初始化Request。前缀为If
的headers规定了服务器只能返回符合这些描述的资源,若不符合, 则会返回304 Not Modified
。
5.3.3 Request Body
若Request-Line
中的Method
为GET
,请求中不包含消息体,若为POST
,则会包含消息体。
5.3.4 一个具体的Request消息实例:
GET /articles/http-basics HTTP/1.1
Host: www.articles.com
Connection: keep-alive
Cache-Control: no-cache
Pragma: no-cache
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
5.4 Response消息体
Response消息格式和Request类似,也分为三部分:Response-Line
、Response Headers
、Response Body
。
5.4.1 Response-Line
Response-Line具体定义如下:
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
HTTP-Version
字段值一般为HTTP/1.1
Status-Code
前面已经讨论过了Reason-Phrase
是对status code
的具体描述
一个最常见的Response响应为:
HTTP/1.1 200 OK
5.4.2 Response Headers
下面是response-header
的定义:
response-header = Accept-Ranges
| Age
| ETag
| Location
| Proxy-Authenticate
| Retry-After
| Server
| Vary
| WWW-Authenticate
Age
表示消息自server生成到现在的时长,单位是秒ETag
是对Entity进行MD5 hash运算的值,用来检测更改Location
被重定向的URLServer
服务器标识
参考资料:
http://code.tutsplus.com/tutorials/http-the-protocol-every-web-developer-must-know-part-1–net-31177
https://zh.wikipedia.org/wiki/%E8%B6%85%E6%96%87%E6%9C%AC%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE