HTTP代表超文本传输协议。它是用于在分布式系统之间进行通信的无状态应用层协议,是现代网络的基础。作为网络开发人员,我们都必须对此协议有很强的理解。
我们来看看这个功能强大的协议,通过web开发者的镜头。我们将分两部分来处理这个问题。在这第一个条目中,我们将介绍基本知识并概述各种请求和响应头。在后续文章中,我们将回顾一下特定的HTTP - 即缓存,连接处理和身份验证。
HTTP基础知识
HTTP允许各种主机和客户端之间的通信,并支持网络配置的混合。
为了实现这一点,它对于特定系统的假设很少,并且不会在不同的消息交换之间保持状态。
这使得HTTP成为无状态协议。通信通常通过TCP / IP进行,但可以使用任何可靠的传输。TCP / IP的默认端口为80,但也可以使用其他端口。
自定义标头也可以由客户端创建和发送。
通过请求/响应对发生主机和客户端之间的通信。客户端发起一个HTTP请求消息,它通过HTTP响应消息进行服务。我们将在下一节中看这个基本的消息对。
当前版本的协议是HTTP / 1.1,它为之前的1.0版本增加了一些额外的功能。在我看来,最重要的是包括持久连接,分块传输编码和细粒度缓存头。本文将简要介绍这些功能; 第二部分将提供深入的报道。
网址
Web通信的核心是通过统一资源定位器(URL)发送的请求消息。我相信你已经熟悉了URL,但为了完整起见,我将其包含在这里。URL具有由以下组件组成的简单结构:
协议通常是http
,但它也可以https
用于安全通信。默认端口是80
,但可以明确设置,如上图所示。资源路径是服务器上资源的本地路径。
动词
还有Web调试代理,如Windows上的Fiddler和OSX的Charles Proxy。
URL显示了我们想要通信的特定主机的身份,但是应该通过HTTP动词指定在主机上执行的操作。当然,客户端希望主机执行几种操作。HTTP已经形式化了一些捕获普遍适用于各种应用程序的要点。
这些请求动词是:
- GET:获取现有资源。该URL包含服务器查找和返回资源所需的所有必要信息。
- POST:创建一个新的资源。POST请求通常携带指定新资源的数据的有效载荷。
- PUT:更新现有资源。有效载荷可能包含资源的更新数据。
- 删除:删除现有资源。
上述四个动词是最受欢迎的,大多数工具和框架明确地暴露了这些请求动词。PUT
并且DELETE
有时被认为是POST
动词的特殊版本,并且它们可以被打包成POST
具有包含确切动作的有效载荷的请求:创建,更新或删除。
HTTP还支持一些较小使用的动词:
- HEAD:这与GET类似,但没有消息体。它用于检索特定资源的服务器头,通常通过时间戳检查资源是否已更改。
- TRACE:用于检索请求从服务器往返的跳数。每个中间代理或网关将其IP或DNS名称注入
Via
到头域中。这可以用于诊断目的。 - 选项:用于检索服务器功能。在客户端,可以根据服务器支持的方式修改请求。
状态码
使用URL和动词,客户端可以向服务器发起请求。作为回报,服务器响应状态码和消息有效载荷。状态代码很重要,并告诉客户端如何解释服务器响应。HTTP规范为特定类型的响应定义了一些数字范围:
1xx:信息消息
所有HTTP / 1.1客户端都需要接受
Transfer-Encoding
标头。
这类代码是在HTTP / 1.1中引入的,完全是临时的。服务器可以发送Expect: 100-continue
消息,告诉客户端继续发送请求的剩余部分,或者如果已经发送请求,则忽略该消息。HTTP / 1.0客户端应该忽略此头。
2xx:成功
这告诉客户端请求已成功处理。最常见的代码是200 OK。对于GET
请求,服务器在消息正文中发送资源。还有其他较少使用的代码:
- 202已接受:请求被接受,但可能不包括响应中的资源。这对服务器端的异步处理非常有用。服务器可以选择发送监控信息。
- 204无内容:回复中没有留言体。
- 205重置内容:指示客户端重置其文档视图。
- 206部分内容:表示响应只包含部分内容。附加标题表示确切的范围和内容过期信息。
3xx:重定向
404表示资源无效,服务器上不存在。
这需要客户端采取额外的措施。最常见的用例是跳转到不同的URL以获取资源。
- 301永久移动:资源现在位于新的URL。
- 303请参阅其他:资源暂时位于新的URL。该
Location
响应报头包含临时URL。 - 304未修改:服务器已确定资源未更改,客户端应使用其缓存副本。这取决于客户端发送
ETag
(Enttity Tag)信息是内容的哈希的事实。服务器将其与其自己计算的进行比较ETag
以检查修改。
4xx:客户端错误
当服务器认为客户端出现故障时,会使用这些代码,无论是通过请求无效资源还是发出不良请求。这个类中最流行的代码是404 Not Found,我认为每个人都会识别。404表示资源无效,服务器上不存在。该课程中的其他代码包括:
- 400错误请求:请求格式错误。
- 401未经授权:请求需要身份验证。客户端可以使用
Authorization
头重复请求。如果客户端已经包含了Authorization
标题,那么凭据是错误的。 - 403禁止:服务器已拒绝对资源的访问。
- 405方法不允许:在请求行中使用无效的HTTP动词,或服务器不支持该动词。
- 409冲突:服务器无法完成请求,因为客户端正在尝试修改比客户端时间戳更新的资源。在协作编辑资源时,冲突主要出现在PUT请求中。
5xx:服务器错误
此类代码用于在处理请求时指示服务器故障。最常用的错误代码是500内部服务器错误。这个班的其他人是:
- 501未实现:服务器不支持所请求的功能。
- 503服务不可用:如果服务器上的内部系统发生故障或服务器超载,可能会发生这种情况。通常,服务器甚至不会响应,请求将超时。
请求和响应消息格式
到目前为止,我们已经看到URL,动词和状态码构成了HTTP请求/响应对的基本部分。
在来看看这些消息的内容。HTTP规范指出请求或响应消息具有以下通用结构:
message = <start-line> *(<消息头>) CRLF [<消息主体>] <start-line> =请求线| 状态行 <message-header> = Field-Name':'Field-Value
必须在邮件标题和正文之间放置一行。该消息可以包含一个或多个标头,其大小分为:
消息体可以包含完整的实体数据,或者如果使用分块编码(Transfer-Encoding: chunked
),则它可能是零碎的。所有HTTP / 1.1客户端都需要接受Transfer-Encoding
标头。
总干事
有几个标头(通用标题)由请求和响应消息共享:
general-header = Cache-Control | 连接 | 日期 | 附注 | 拖车 | 传输编码 | 升级 | 通过 | 警告
我们已经看到一些这些头,具体Via
和Transfer-Encoding
。我们将覆盖Cache-Control
和Connection
分两部分。
状态代码很重要,并告诉客户端如何解释服务器响应。
Via
标题用于TRACE消息,并由所有间歇性代理和网关更新Pragma
被认为是一个自定义标题,可以用于包括实现特定的头。最常用的pragma指令是Pragma: no-cache
,它实际上是Cache-Control: no-cache
HTTP / 1.1。这将在本文的第2部分中介绍。- 的
Date
报头字段被用于时间戳请求/响应消息 Upgrade
用于切换协议,并允许平滑过渡到较新的协议。Transfer-Encoding
通常用于将响应分解成具有该Transfer-Encoding: chunked
值的较小部分。这是HTTP / 1.1中的一个新标题,允许对客户端而不是一个大的有效载荷进行响应流。
实体头
请求和响应消息还可以包括实体头部以提供关于内容的元信息(也称为消息体或实体)。这些标题包括:
entity-header = Allow | 内容编码 | 内容语言 | 内容长度 | 内容位置 | 内容-MD5 | 内容范围 | 内容类型 | 过期 | 上一次更改
所有Content-
前缀头提供有关消息体结构,编码和大小的信息。如果实体是邮件的一部分,则这些头文件中的一些需要存在。
该Expires
头表示了when的时间戳他实体到期。有趣的是,将来会发送一个“永不过期”实体,时间戳为一年。该Last-Modified
头表示该实体的最近的修改时间。
自定义标头也可以由客户端创建和发送; 它们将被HTTP协议视为实体头。
这实际上是一种扩展机制,一些客户端 - 服务器实现可以选择在这些扩展头上进行专门的通信。虽然HTTP支持自定义标头,但它真正寻找的是请求和响应标头,我们将在下面介绍。
请求格式
请求消息具有与上述相同的通用结构,但请求行除外:
Request-Line =方法SP URI SP HTTP-Version CRLF Method =“OPTIONS” | “头” | “得到” | “POST” | “放” | “删除” | “跟踪”
SP
是令牌之间的空格分隔符。HTTP-Version
被指定为“HTTP / 1.1”,然后是新行。因此,典型的请求消息可能如下所示:
GET / articles / http-basics HTTP / 1.1 主持人:www.articles.com 连接:保持活着 缓存控制:无缓存 Pragma:无缓存 接受:text / html,application / xhtml + xml,application / xml; q = 0.9,* / *; q = 0.8
请注意请求行后跟许多请求标头。该主机头是必须的HTTP / 1.1客户端。GET请求没有邮件正文,但POST请求可以包含正文中的帖子数据。
请求标头作为请求消息的修饰符。已知请求标题的完整列表不会太长,并在下面提供。未知标头被视为实体头字段。
request-header = Accept | 接收字符 | 接受编码 | 接受语言 | 授权 | 期望 | 从 | 主办 | 如果-匹配 | 如果-Modified-Since的 | 如果 - 无 - 匹配 | 如果量程 | 如果未修饰的,因为 | 马克斯 - 前锋 | 代理授权 | 范围 | 引荐 | TE | 用户代理
该Accept
前缀头表明可接受的媒体类型,在客户端上语言和字符集。From
,Host
,Referer
并User-Agent
找出关于发起请求的客户端的详细信息。该If-
前缀头是用来做请求多个条件,并且服务器只返回如果条件相匹配的资源。否则返回304 Not Modified
。条件可以基于时间戳或ETag(实体的哈希)。
响应格式
响应格式类似于请求消息,除了状态行和标题。状态行具有以下结构:
状态行= HTTP版本SP状态代码SP原因短语CRLF
- HTTP版本发送为
HTTP/1.1
- 状态代码是前面讨论的许多状态之一。
- 原因短语是状态码的人性化版本。
成功响应的典型状态行可能如下所示:
HTTP / 1.1 200 OK
响应标题也是相当有限的,全集如下:
response-header = Accept-Ranges | 年龄 | ETag的 | 位置 | 代理服务器进行身份验证 | 重发后 | 服务器 | 变化 | WWW身份验证
Age
是在服务器上生成消息后的几秒钟内的时间。ETag
是实体的MD5哈希,用于检查修改。Location
用于发送重定向并包含新的URL。Server
标识生成消息的服务器。
到目前为止,这是一个很大的理论,所以我不会怪你瞌睡的眼睛。在接下来的章节中,我们将更加实用,并对工具,框架和库进行调查。
在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:获取请求体。
- req.query:获取URL的查询片段。
- req.originalUrl
- req.host:读取
Host
头字段。 - req.accepts:在客户端读取可接受的MIME类型。
- req.get OR req.header:读取作为参数传递的任何头字段。
在出口到客户端的路上,ExpressJS提供以下响应API:
- res.status:设置一个显式的状态码。
- res.set:设置一个特定的响应头。
- res.send:发送HTML,JSON或八位字节流。
- res.sendFile:将文件传输到客户端。
- res.render:渲染快照视图模板。
- res.redirect:重定向到不同的路由。Express自动添加默认重定向代码302。
Ruby on Rails
请求和响应消息大部分是相同的,除了第一行和消息头。
在Rails中,ActionController和ActionDispatch模块提供了用于处理请求和响应消息的API。
ActionController提供了一个高级API来读取请求URL,渲染输出并重定向到另一个终点。端点(aka route)作为一个动作方法处理。大多数的行动的方法中必要的上下文信息经由提供request
,response
和params
对象。
- 参数:可以访问URL参数和POST数据。
- 请求:包含有关客户端,头文件和URL的信息。
- 响应:用于设置标题和状态代码。
- 渲染:通过展开模板来呈现视图。
- redirect_to:重定向到其他动作方法或URL。
ActionDispatch通过ActionDispatch::Request
和ActionDispatch::Response
类提供对请求/响应消息的细粒度访问。它公开了一组查询方法来检查请求的类型(get?()
,post?()
,head?()
,local?()
)。可以通过该request.headers()
方法直接访问请求头。
在响应方面,它提供方法来设置cookies()
,location=()
和status=()
。如果你觉得冒险,你也可以设置body=()
和绕过Rails渲染系统。
jQuery Ajax
因为jQuery主要是一个客户端库,它的Ajax API与服务器端框架相反。换句话说,它允许您读取响应消息并修改请求消息。jQuery通过jQuery.ajax(设置)公开一个简单的API :
通过传回settings
具有beforeSend
回调的对象,我们可以修改请求头。回调接收jqXHR(jQuery XMLHttpRequest)对象,该对象公开了一个调用setRequestHeader()
来设置头文件的方法。
$就({ url:'http://www.articles.com/latest', 键入:'GET', beforeSend:function(jqXHR){ jqXHR.setRequestHeader('Accepts-Language','en-US,en'); } });
- jqXHR对象也可以用来读取响应头
jqXHR.getResponseHeader()
。 - 如果要针对各种状态代码采取具体操作,可以使用
statusCode
回调:
$就({ statusCode:{ 404:function(){ 警报(“找不到页面”); } } });
概要
这样总结了我们对HTTP协议的快速浏览。
我们审查了URL结构,动词和状态代码:HTTP通信的三大支柱。
请求和响应消息大部分是相同的,除了第一行和消息头。最后,我们回顾了如何修改Web框架和库中的请求和响应头。
了解HTTP对于在两个端点之间建立一个干净,简单和RESTful的接口至关重要。在更大规模上,它也有助于设计您的网络基础设施,并为您的最终用户提供一个很好的体验。