HTTP:每个Web开发人员都必须知道的协议 - 第1部分
原文更新于20130408,文章基于HTTP / 1.1
code.tutsplus.com/tutorials/h…
摘要:
-
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
-
Hypertext Transfer Protocol,分布式系统间的无状态的应用层协议,现代web基础
-
through the lens of 从...视角
-
基本内容并概述各种请求和响应头
-
HTTP允许在各种主机和客户机之间进行通信,并支持混合的网络配置。(决定了无状态和不对特定的系统做出假设)
-
a variety of 各种
-
使用TCP/IP,或者其他可靠的传输协议。默认端口80
-
客户端创建自定义的头部发送到服务端
-
host和client通过request/response来进行通信
-
a few 一些、几个
-
HTTP/1.1新增了几个重要的特性:包括长连接(persistent connections)、分块传输编码(chunked transfer-coding)、细粒度缓存头部 (fine-grained caching headers)。
-
completeness 完整性
-
常用HTTP verbs:
- GET: fetch an existing resource.
- POST: create a new resource.
- PUT: update an existing resource.
- DELETE: delete an existing resource.
-
用的较少的HTTP verbs:
- HEAD: this is similar to GET, but without the message body. (通常通过时间戳检查资源是否已更改。)
- TRACE: used to retrieve the hops that a request takes to round trip from the server. (用于诊断)
- OPTIONS: used to retrieve the server capabilities(用于检索服务器功能).
-
通过url和动词,客户机可以向服务器发起请求。作为响应,服务器使用状态代码和消息有效负载进行响应。
-
状态码很重要,告诉client如何翻译server的响应
-
1xx: Informational Messages
- 服务端发送
Expect: 100-continue消息,告诉客户端继续发送剩余的请求
- 服务端发送
-
2xx: Successful
- 200 OK,对于
GET请求,服务端将请求的资源放在消息体中发送给client - 202 Accepted,请求i成功接收,但是响应中的消息体中不会包含资源,在服务端异步处理时很有用。
- 204 No Content: 响应中没有消息体
- 205 Reset Content: 指示客户端重置其文档视图。
- 206 Partial Content
- 200 OK,对于
-
3xx: Redirection
- 301 Moved Permanently,资源在新的URL
- 303 See Other:资源暂时位于一个新的URL,
Loacationresponse header 包含临时的URL - 304 Not Modified: 使用缓存,这个依赖client发送ETag(Enttity Tag)信息(内容hash),服务器用这个ETag和自己计算的ETag比较来检查更改
-
4xx: Client Error 服务端认为客户端发生了错误(请求非法资源,发送错误请求)
- 404 not Found 表明资源非法,服务端不存在
- 400 Bad Request: the request was malformed(畸形的)
- .401 Unauthorized: request requires authentication. 客户端可以包含
Authorizationheader重新发起请求,如果已经包含了Authorization header,那么credentials(证书)错误 - 403 Forbidden:服务端拒绝获取该资源
- 405 Method Not Allowed: 非法的HTTP verb,或者不支持这个verb
- 409 Conflict:服务器无法完成请求,因为客户机试图修改比客户机的时间戳更新的资源。冲突主要发生在对资源进行协作编辑期间的PUT请求。
-
5xx: Server Error
- 500 Internal Server Error
- 501 Not Implemented: 服务端不支持请求的functionality
- 503 Service Unavailable: 如果服务器上的内部系统失败或服务器过载,就会发生这种情况。通常,服务器甚至不会响应,请求将超时。
-
Request and Response Message Formats 请求和响应消息格式
-
URLs,verbs和status codes(状态码)组成了HTTP请求/响应对的基本部分
-
HTTP规范声明请求或响应消息具有以下通用结构:
-
message = <start-line> *(<message-header>) CRLF [<message-body>] <start-line> = Request-Line | Status-Line <message-header> = Field-Name ':' Field-Value -
mandatory 强制的
-
消息可以包含一个或者多个headers
-
general headers: that are applicable for both request and response messages.请求头和响应头通用
-
general-header = Cache-Control | Connection | Date | Pragma | Trailer | Transfer-Encoding | Upgrade | Via | Warning -
via 用于TRACE 消息, 由all intermittent proxies and gateways更新
-
PragmaPragma: no-cache, which really isCache-Control: no-cacheunder HTTP/1.1. This will be covered in Part 2 of the article.自定义头部 -
Date request/response的时间戳
-
Upgrade协议升级(switch protocols and allow a smooth transition to a newer protocol). -
Transfer-Encoding分块值将响应分解为更小的部分。
-
-
request specific headers.
-
response specific headers.
-
entity headers.
-
请求和响应都可能包含entity headers来提供meta-information(元信息),这些信息关于content(aka Message Body or Entity 又叫做消息体或者实体)
-
entity-header = Allow | Content-Encoding | Content-Language | Content-Length | Content-Location | Content-MD5 | Content-Range | Content-Type | Expires | Last-Modified -
所有的content- prefixed前缀的headers提供了消息体结构,编码和长度的信息
-
last-modified报头指示实体的最后修改时间戳。 -
Expires` header指示了entity何时过期的时间戳 (timestamp)
-
客户端还可以创建和发送自定义头文件;它们将被HTTP协议视为实体头。
-
-
-
-
-
Request Format 请求格式
-
Request-Line = Method SP URI SP HTTP-Version CRLF Method = "OPTIONS" | "HEAD" | "GET" | "POST" | "PUT" | "DELETE" | "TRACE" -
GET请求没有消息体,但是POST请求可以在消息体中包含POST数据。 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 -
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 -
Accept 前缀表明client 可接受的媒体类型(media-types),语言和字符集
-
From,Host,RefererandUser-Agent表明初始化请求的client的细节 -
If- 前缀为请求添加条件限制,只有条件满足,server才返回资源数据,否则返回
304 Not Modified -
条件基于时间戳或者ETag( 实体的hash)
-
-
Response Format
-
响应格式于请求格式相似,处理status line 和headers
-
status line结构
-
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF -
HTTP-Version is sent as HTTP/1.1
-
The Status-Code 200 301 304 ....
-
状态码的人类可读版本.
-
成功的响应典型的 status line
HTTP/1.1 200 OK
-
-
response-header
-
response-header = Accept-Ranges | Age | ETag | Location | Proxy-Authenticate | Retry-After | Server | Vary | WWW-Authenticate -
Age是自消息在服务器上生成以来以秒为单位的时间。
-
ETag是实体的MD5散列,用于检查修改。
-
location用于发送重定向并包含新URL。
-
Server 标识生成消息的服务器。
-
-
HTTP代表超文本传输协议(Hypertext Transfer Protocol)。 它是用于在分布式系统(distributed systems)之间进行通信的无状态应用层协议,是现代Web的基础。 作为Web开发人员,我们都必须对此协议有深刻的理解( strong understanding )。
让我们通过Web开发人员的视角来回顾这个强大的协议。 我们将分两部分来讨论这个话题。 在第一个部分中(In this first entry),我们将介绍基础知识并概述各种请求和响应头部。 在后续文章中( In the follow-up article),我们将回顾特定的HTTP部分 - 即缓存,连接处理和身份验证。
虽然我会提到一些与HTTP头部相关的细节,但最好先参考RFC (RFC 2616) 进行深入了解。 我将在整篇文章中指出RFC的特定部分。
寻找快速解决方案?
如果您在WordPress中遇到需要修复的HTTP错误,可以订购 Express HTTP error fix 在Envato Studio上,只需50美元即可在一天内修复错误。

HTTP基础知识
HTTP允许各种主机和客户端之间的通信,并支持混合的网络配置。
为了实现这一点,它对于某个特定系统做出很少假设,并且不保持不同消息交换之间的状态。
这使得HTTP成为了一个 无状态 协议(stateless protocol)。 通信通常通过TCP / IP进行,但可以使用任何可靠的传输。 TCP / IP的默认端口是 80 ,但也可以使用其他端口。

客户端也可以创建和发送自定义HTTP头部。
主机和客户端之间的通信通过请求/响应对进行 。 客户端发起HTTP请求消息,主机通过HTTP响应消息进行服务。 我们将在下一节中讨论这个基本的消息对。
该协议的当前版本是 HTTP / 1.1 ,它为之前的1.0版本增加了一些额外的功能。 在我看来,其中最重要的包括 持久连接 , 分块传输编码 和 细粒度的缓存头 。 我们将在本文中简要介绍这些功能; 第二部分将提供深入的报道。
URLs
Web通信的核心是请求消息,它通过统一资源定位符(URLs)发送。 我相信你已经熟悉了URLs,但为了完整起见,我将把它包含在这里。 URL具有由以下组件组成的简单结构:

该协议通常是 http ,但它也可以 HTTPS 用于安全通信。 默认端口是 80 ,但可以明确设置一个,如上图所示( as illustrated in the above image)。 资源路径是服务器上资源的本地路径。
动词
还有Web调试代理,比如 Windows上的 Fiddler OSX上的Charles Proxy。
URLs显示我们要与之通信的特定主机的标识,但应通过HTTP谓词指定应在主机上执行的操作。 当然,客户希望主机执行多项操作。 HTTP已经将一些普遍适用于各种应用程序的基本要素的verbs进行了正式化。
这些请求动词(request verbs)是:
- GET : 取 现有资源(fetch an existing resource )。 URL包含服务器查找和返回资源所需的所有必要信息。
- POST : 创建 一种新的资源。 POST请求通常携带有效负载,指定新资源的数据。
- PUT : 更新 现有资源。 有效载荷(payload)可以包含资源的更新数据。
- DElETE: 删除 现有资源。
以上四个动词是最受欢迎的,大多数工具和框架都明确地公开了这些动词。 PUT和 DELETE 有时被认为是特殊版本的 POST 动词,它们可以打包成 POST 请求包含确切操作的有效负载: 创造 , 更新 或 删除 (create, update or delete) 。
HTTP还支持一些较少使用的动词:
- HEAD :这与GET类似,但没有消息体。 它用于检索特定资源的服务器头文件(It's used to retrieve the server headers for a particular resource),通常是通过时间戳检查资源是否已更改。
- TRACE :用于检索请求从服务器返回所需的跳转。每个中间代理或网关都将其
IP或DNS名称注入Via头部。这可以用于诊断目的。 - OPTIONS :用于检索服务器功能。 在客户端,它可以用于根据服务器可以支持的内容修改请求。
Status Codes
使用URLs和verbs,客户端可以向服务器发起请求。 作为响应(in return),服务器响应状态代码(status code)和消息有效负载(message payloads)。 状态代码很重要,它告诉客户端如何翻译(interpret)服务器响应。 HTTP规范为特定类型的响应定义了某些数字范围:
1xx:信息性消息(Informational Messages)
所有HTTP / 1.1客户端都必须接受
Transfer-Encoding头部。
这类代码是在HTTP / 1.1中引入的,纯粹是临时的。 服务器可以发送一个Expect: 100-continue 消息,告诉客户端继续发送请求的其余部分,或忽略它是否已发送它。 HTTP / 1.0客户端应该忽略此标头。
2xx:成功(Successful)
这告诉客户端请求已成功处理。 最常见的代码是 200好的 。 为一个 得到 请求,服务器在消息体中发送资源。 还有其他不太常用的代码:
- 202 已接受(Accepted):请求已被接受但可能不包含响应中的资源。 这对于服务器端的异步处理很有用。 服务器可以选择发送用于监视的信息。
- 204 无内容(No Content):响应中没有消息正文。
- 205 重置内容(Reset Content):指示客户端重置其文档视图。
- 206 部分内容(Partial Content):表示响应仅包含部分内容。 其他标头指示确切的范围和内容到期信息。
3xx:重定向(Redirection)
404表示资源无效且服务器上不存在。
这要求客户采取其他措施。 最常见的用例是跳转到不同的URL以获取资源。
- 301 永久移动(Moved Permanently):资源现在位于新URL。
- 303 请参阅其他(See Other):资源临时位于新URL。 该 地点 响应头包含临时URL。
- 304 未修改(Not Modified):服务器已确定资源未更改,客户端应使用其缓存副本。 这取决于客户端发送的事实 ETag的 (Enttity Tag)信息是内容的散列。 服务器将其与自己的计算结果进行比较 ETag的 检查修改。
4xx:客户端错误(Client Error)
当服务器认为客户端出错时,可以通过请求无效资源或发出错误请求来使用这些代码。 这个类中最常见的代码是 404 Not Found ,我认为每个人都会认同。 404表示资源无效且服务器上不存在。 此类中的其他代码包括:
- 400 错误请求(Bad Request):请求格式错误。
- 401 未经授权(Unauthorized):请求需要身份验证。 客户端可以重复请求 授权 头。 如果
client已经包含了Authorization头部,那么认证消息(credentials )是错误的。 - 403 禁止访问(Forbidden):服务器已拒绝访问该资源。
- 405 方法不允许(Method Not Allowed):请求行中使用的HTTP谓词无效,或者服务器不支持该verb。
- 409 冲突(Conflict):服务器无法完成请求(could not complete the request ),因为客户端正在尝试修改比客户端时间戳更新的资源。 在资源的协作编辑期间,冲突主要出现在PUT请求中。
5xx:服务器错误(Server Error)
此类代码用于指示处理请求时服务器故障。 最常用的错误代码是 500内部服务器错误(Internal Server Error) 。 这类代码中的其他是:
- 501未实现 (Not Implemented):服务器尚不支持所请求的功能。
- 503服务不可用 ( Service Unavailable):如果服务器上的内部系统出现故障或服务器过载,则可能发生这种情况。 通常,服务器甚至不响应,请求将超时。
请求和响应消息格式
到目前为止,我们已经看到了这一点 网址,动词和状态代码 构成HTTP请求/响应对的基本部分。

现在让我们看一下这些消息的内容。 HTTP规范声明请求或响应消息具有以下通用结构:
message = <start-line>
*(<message-header>)
CRLF
[<message-body>]
<start-line> = Request-Line | Status-Line
<message-header> = Field-Name ':' Field-Value
必须在消息headers和body之间放置一个新行。 该消息可以包含一个或多个头部,其中大致分为:
- general headers: that are applicable for both request and response messages.
- request specific headers.
- response specific headers.
- entity headers.
消息体可以包含完整的实体数据,或者如果使用分块编码( Transfer-Encoding:chunked ) ,它可能是零碎的 。 所有HTTP / 1.1客户端都必须接受Transfer-Encoding头。
General Headers
请求和响应消息共享一些头部(General Headers):
general-header = Cache-Control
| Connection
| Date
| Pragma
| Trailer
| Transfer-Encoding
| Upgrade
| Via
| Warning
我们已经看到了一些头部,特别是Via和 Transfer-Encoding 。 我们将在第二部分介绍Cache-Control和Connection。
status code很重要,它告诉客户端如何解释服务器响应。
Via标头用于TRACE消息,并由所有间歇性代理和网关更新Pragma(注解) 被认为是自定义标头,可用于包含实现特定的头部。 最常用的注解指令(pragma-directive)是Pragma: no-cache,对应于HTTP / 1.1下Cache-Control: no-cache。 这将在本文的第2部分中介绍。Date头部字段用于对请求/响应消息加时间戳Upgrade用于切换协议并允许平滑过渡到较新的协议。Transfer-Encoding通常用于将响应分解为更小的部分 转移编码:分块 值。 这是HTTP / 1.1中的新标头,允许将响应流传输到客户端而不是一个大的有效负载。
Entity headers
请求和响应消息还可以包括实体头部(Entity headers)以提供关于内容的元信息(meta-information)(也称为消息主体或实体 aka Message Body or Entity)。 这些头部包括:
entity-header = Allow
| Content-Encoding
| Content-Language
| Content-Length
| Content-Location
| Content-MD5
| Content-Range
| Content-Type
| Expires
| Last-Modified
全部 content- 前缀的标头提供有关消息正文的结构,编码和大小的信息(structure, encoding and size of the message body)。 如果实体是消息的一部分,则需要像是其中一些头部。
Expires 头部表示实体(entity)到期时的时间戳。 有趣的是,一个 “永不过期” 实体以未来一年的时间戳发送。 Last-Modified 头部表示实体的最后修改时间戳。
客户端也可以创建和发送自定义头部; 它们将被HTTP协议视为实体头。
这实际上是一种扩展机制,并且一些客户端 - 服务器实现可以选择通过这些扩展头部特定地进行通信。 虽然HTTP支持自定义头部,但它真正寻找的是请求和响应头部,我们将在下面介绍它们(Although HTTP supports custom headers, what it really looks for are the request and response headers, which we cover next.)。
请求格式
请求消息具有与上面相同的通用结构,但请求行看起来像:
Request-Line = Method SP URI SP HTTP-Version CRLF
Method = "OPTIONS"
| "HEAD"
| "GET"
| "POST"
| "PUT"
| "DELETE"
| "TRACE"
SP 是tokens之间的空格分隔符。 HTTP-Version 被指定为 “HTTP / 1.1” 然后是新的一行。 因此,典型的请求消息可能如下所示:
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
请注意请求行后跟许多请求头部。 该Host头部对于HTTP / 1.1客户端是必需的。 GET 请求没有消息体,但是 POST 请求可以包含正文中的post数据。
请求头部充当请求消息的修饰符。 已知请求标头的完整列表不会太长,并在下面提供。 未知头部被视为实体头部字段(entity-header fields)。
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
Accept前缀的头部表示客户端上可接受的媒体类型,语言和字符集。 From, Host, Referer and User-Agent识别有关发起请求的客户端的详细信息。 该 If- 前缀标头用于使请求更具条件性,服务器仅在条件匹配时才返回资源。 否则,它返回一个 304未修改 。 条件可以基于时间戳或ETag(实体的散列)。
响应格式
响应格式类似于请求消息,状态行和标题除外。 状态行具有以下结构:
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
HTTP-Version作为发送 HTTP / 1.1Status-Code是前面讨论的众多状态之一。Reason-Phrase是状态代码的人类可读版本。
成功响应的典型状态行可能如下所示:
HTTP / 1.1 200 OK
响应头也相当有限,完整集如下:
response-header = Accept-Ranges
| Age
| ETag
| Location
| Proxy-Authenticate
| Retry-After
| Server
| Vary
| WWW-Authenticate
Age是自服务器上生成消息以来的秒数。ETag的 是实体的MD5哈希,用于检查修改。Location在发送重定向时使用并包含新URL。Server标识生成消息的服务器。
到目前为止,这已经是很多理论,所以我不会因为昏昏欲睡的眼睛而责怪你。 在接下来的部分中,我们将更加实用,并对工具,框架和库进行调查。
查看HTTP流量的工具
有许多工具可用于监视HTTP通信。 在这里,我们列出了一些比较流行的工具。
毫无疑问, Chrome / Webkit检查员 是Web开发人员的最爱:

还有Web调试代理,比如Windows的 Fiddler 和 OSX的Charles Proxy 。 我的同事Rey Bango写了一篇 excellent article 关于这个话题。


对于命令行,我们有像 curl, tcpdump 和tshark 用于监控HTTP流量。
在Web框架和库中使用HTTP
现在我们已经查看了请求/响应消息,现在是时候了解库和框架如何以API的形式公开它。 我们会用的 ExpressJS for Node , Ruby on Rails ,和 jQuery Ajax 作为我们的例子。
ExpressJS
如果您在NodeJS中构建Web服务器,那么您考虑的可能性很高 ExpressJS.。 ExpressJS最初的灵感来自一个名为Sinatra的Ruby Web框架。 正如预期的那样,API也受到同样的影响。
因为我们正在处理服务器端框架,所以在处理HTTP消息时有两个主要任务:
- 读取URL片段和请求标头。
- 写回复标题和正文
了解HTTP对于在两个端点之间建立干净,简单且RESTful的接口至关重要。
ExpressJS提供了一个简单的API来实现这一目标。 我们不会介绍API的详细信息。 相反,我们将提供ExpressJS指南详细文档的链接。 在大多数情况下,API中的方法是不言自明的。 以下是与请求相关的API的示例:
-
req.body: get the request body.
-
req.query: get the query fragment of the URL.
-
req.host: reads the
Hostheader field. -
req.accepts: reads the acceptable MIME-types on the client side.
-
req.get OR req.header: read any header field passed as argument.
在前往客户端的路上,ExpressJS提供以下响应API:
-
[res.status: set an explicit status code.
-
res.set: set a specific response header.
-
res.send: send HTML, JSON or an octet-stream.
-
res.sendFile: transfer a file to the client.
-
res.render: render an express view template.
-
res.redirect: redirect to a different route. Express automatically adds the default redirection code of 302.
Ruby on Rails
除第一行和消息头之外,请求和响应消息大致相同。
在Rails中,the ActionController and ActionDispatch 模块提供用于处理请求和响应消息的API。
ActionController提供高级API来读取请求URL,呈现输出并重定向到不同的端点。 端点(aka路径)作为动作方法处理。 大多数必要的上下文信息都是通过request, reponse和 ``params`对象等action-method提供。
- params: gives access to the URL parameters and POST data.
- request: contains information about the client, headers and URL.
- response: used to set headers and status codes.
- render: render views by expanding templates.
- redirect_to: redirect to a different action-method or URL.
ActionDispatch 提供对请求/响应消息的细粒度访问, 通过 ActionDispatch::Request 和 ActionDispatch::Response 类. 它暴露一组查询方法来检查请求的类型 (get?(), post?(), head?(), local?()). 可以通过request.headers() 方法直接访问请求标头 .
在响应端,它提供了要设置响应头部的方法cookies(), location=() 和 status=(). 如果你喜欢冒险,你也可以设置 body=() 并绕过Rails呈现系统.
jQuery Ajax
因为jQuery主要是一个客户端库, its Ajax API 提供了服务器端框架的对立面. 换言之(In other words), 允许你 read响应消息并且 modify 请求消息. jQuery通过 jQuery.ajax(settings)来暴露自己的API:
传入含有beforeSend回调方法的 settings 对象, 我们可以修改请求头. 回调函数接受 jqXHR (jQuery XMLHttpRequest) 对象作为参数,这个对象包含设置请求头的方法 setRequestHeader() .
$.ajax({
url: 'http://www.articles.com/latest',
type: 'GET',
beforeSend: function (jqXHR) {
jqXHR.setRequestHeader('Accepts-Language', 'en-US,en');
}
});
- The jqXHR object can also be used to read the response headers with the
jqXHR.getResponseHeader(). - If you want to take specific actions for various status codes, you can use the
statusCodecallback:
$.ajax({
statusCode: {
404: function() {
alert("page not found");
}
}
});
总结(Summary)
这就是我们对HTTP协议的快速浏览。
我们回顾了URL结构、动词和状态代码:HTTP通信的三大支柱。
了第一行和消息头之外,请求和响应消息几乎是相同的。最后,我们讨论了如何在web框架和库中修改请求和响应头。
理解HTTP对于在两个端点之间拥有一个干净、简单和RESTful的接口至关重要。在更大的范围内,它还有助于设计网络基础设施,并为最终用户提供良好的体验。
在第2部分中,我们将回顾连接处理、身份验证和缓存!到时候见。