(译)Web是如何工作的(3):HTTP&REST

 
我们在第一篇文章中介绍了基本的Web架构,然后在第二篇文章中谈论了Web应用程序的结构,现在是时候卷起袖子来近距离看看HTTP和REST。
 
对于Web开发人员,是必须理解HTTP的,因为是HTTP使得信息可以在Web应用中传递——允许更好的用户交互和提高网站的性能。

什么是HTTP?

 在客户端-服务器模型中,客户端和服务器是以“请求-响应”消息方式来交互消息的:客户端发送请求,服务器响应请求。
 
跟踪信息的流动比听起来的复杂得多,客户端和服务器都遵循一种通用的语言及一系列规则,所以它们都知道自己需要的是什么,这种语言或者说“协议”就是HTTP。
 
HTTP协议定义了语法(数据格式和编码)、语义(语法的含义)以及即时(速度和顺序)。客户端和服务器之间每个HTTP请求和响应的交换可以认为是单个HTTP事务。

HTTP: 主要内容

 在我们深入探讨HTTP的细节前,有几件事值得一提的。
 
首先,HTTP是基于文本的,这意味着客户端和服务器之间的消息交换是通过比特文本来完成的,每条消息包含两个部分:一个消息首行和一个消息正文。
 
其次,HTTP是应用层协议,意味着它只是一个抽象层标准化主机之间是如何通信的。HTTP本身不能传送数据,它仍然得靠底层的TCP/IP协议在两台机器间获取请求和响应。
 
(提醒一下,TCP/IP是由两部分组成的,它的功能是作为因特网底层“控制系统”,关于TCP/IP的介绍,可以查看这一系列中的第一篇文章)
 
最后,你应该已经在你浏览器的地址栏见过“HTTPS”协议,你会想HTTPS是不是HTTP+“S”,简单的回答是近似,但是还是有点点不同。
 
普通的HTTP请求和响应是没有加密的,很容易受到各种类型的安全攻击。而HTTPS是一种更安全的通信方式,它通过加密的方式使得信息更安全,它是在原有的HTTP数据外面加了一层TLS/SSL。
 
SSL是一种安全协议,它允许客户端与服务器以一种安全的方式在网络中通信,它防止消息在网络传输过程中被窃听和篡改。
 
客户端通常使用一个特殊的端口443来标识是否需要TLS/SSL连接。一旦客户端和服务器同意使用TLS/SSL来通信,他们就通过执行所谓的“TLS握手”来协商建立一个有状态的连接,然后客户端和服务器建立一个会话秘钥,在他们彼此通信时就使用这个秘钥来加密和解密消息。
 
想Google和Facebook这样的大部分网站都使用HTTPS,毕竟它能使你的密码、个人信息和信用卡信息在网络上安全可靠。

HTTP:细节

有了这些基础知识,让我们深入了解一下HTTP的结构。
 
我们通过访问https://www.github.com来与GitHub服务器通信。如果你使用的是谷歌浏览器或者安装了FireBug插件的火狐浏览器,那你可以通过查看“网络”页签来查看HTTP请求的详细信息。如果你已经打开了“网络”页签,然后在你的地址栏里输入www.github.com访问,你应该可以看到类似下图的东西:
 
然后在左表的面板上,首先点击第一条“github.com”,你就可以看到如下图的信息:
 
 

HTTP请求头

HTTP请求头通常包含元数据(关于数据的数据),这些元数据包含请求类型(GET、POST、PUT、DELETE),路径、状态码、内容类型、用户代理、cookie、Post主体(有时包含)等等。
 
用访问Github这个例子,让我们近距离地看一下头部中最重要的部分,我们以“响应头”开始:
  • 请求URL:https://github.com/ (这是我们请求的URL)
  • 请求方法:GET (在这个例子里使用的这种HTTP请求方法,相当于浏览器说:“喂,GitHub服务器,把你的主要给我”)
  • 状态码:200 OK (这是服务器告诉客户端,说你的请求结果正常的一种标准方式。状态码200意味着服务器成功地找到了资源,并正在发送给你)
  • 远程地址:192.30.252.129:443 (这个IP地址和端口号是我们访问的GitHub网站,注意它的端口#443(意思是我们使用的是HTTPS协议,而不是HTTP))
  • 内容编码:gzip (这是我们接受的资源编码,在这个例子里,GitHub服务器告诉我们,它发送回来的内容是压缩过的,GitHub可能压缩了文件,这样你下载时耗时更少。)
  • 内容类型:text/html;字符集=utf-8 (规定响应主体中的数据表示方式,包括类型及其子集,这个类型描述的是数据类型,同时这个子集指定了这个数据类型的特定格式。在我们这个例子里,我们的文本是以HTML的形式返回给我们的;第二部分指定了对于这个HTML文档使用的字符编码,大部分情况下用的是这个例子中的用的UTF-8)
 
头部信息还包含很多内容,它们是客户端必须传送给服务器的,这样服务器才可能知道如何响应请求。下面让我们看一下“请求头”部分:
  • 用户代理:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.73 Safari/537.36 (这表示用户使用的软件,有时网站需要知道它们是如何被浏览的,所以浏览器发送这个用户代理字符串给服务器,服务器可以用来确定访问网站所用的内容)
  • 接收编码:gzip,deflate,sdch (规定浏览器将以什么编码来接收内容,我们可以看到列表中的gzip,这就是为什么GitHub服务器能够发送gzip格式的内容给我们。)
  • 接收语言:en-US;q=0.8 (描述我们想要的网页使用的语言,在这个例子里,“en”代表英语)
  • 主机:github.com (这就不言自明了吧)
  • Cookie:_octo=GH1.1.491617779.1446477115; logged_in=yes; dotcom_user=iam-peekay; _gh_sess=somethingFakesomething FakesomethingFakesomethingFakesomethingFakesomethingFakesomethingFakesomethingFake; user_session=FakesomethingFake somethingFakesomethingFakesomethingFake; _ga=9389479283749823749; tz=America%2FLos_Angeles_ (这段文本是Web服务器存储在用户机器上,以便以后检索,这些信息是以键值对存储的,其中一个键值对是GitHub为了这个请求存储的,例如,“dotcom_user=iam-peekay”是用来告诉GitHub我的用户ID是iam-peekay)

tl;dr:这些键值对又是做什么的?

 长话短说,我们留了很多键值对没有介绍,但是它们是如何生成的?
 
你的浏览器在任何时间访问一个网站时,它都会去查看之前这个网站在你电脑上设置的cookie.
 
所以,如果我访问www.github.com,我的浏览器将查找github保留在我硬盘上的cookie文件,如果找到了cookie文件,它就将把这些键值对包含在请求头里发送给服务器。
 
GitHub网页服务器现在就可以以不同的方式使用cookie数据,比如以用户保存的个人配置来显示内容,以及统计他们访问网站的次数。
 
如果浏览器没有找到cookie文件——这可能是因为之前从没有访问过这个网站或者阻止或删除了cookie——这样浏览器就不会发送任何cookie数据。
 
在这个例子中,GitHub服务器创建了一个新的ID键值对,同时还有任何它需要的键值对,然后通过HTTP头部发送给我的电脑,我的电脑就把这些信息保存在硬盘里。
 

HTTP 主体

 就像上面看到的,服务保留了大部分它需要与客户端通信时用到的重要的元数据。
 
现在回到主体部分。
 
就像你猜的,主体就是信息部分的主体,这看请求类型,主体部分也可以是空的。
 
在我们这个例子了,你在“响应”的页签里可以看到主体部分,自从我们发送了一个Get www.github.com的请求后,这个主体就包含了www.github.com的HTML页面内容。
 
 
当然,这对于展示页面很重要。 

附加练习

 我希望这能让你更好地理解HTTP的结构,作为练习,当你访问www.github.com后,你可以看一下你浏览器请求的其它资源集(比如图片、JS文件等等)
 
 
有了上面的知识,我们可以看一下客户端可以发起的各种HTTP请求方法。
 

HTTP请求方法

 
HTTP动词或者方法,是告诉服务器通过URL中的数据标识去做什么,URL通常是指示一个特定的资源,当客户端使用含有HTTP动词的URL时,这是告诉服务器对于这个资源需要使用什么样的操作。
 
例子:
 
 
当客户端发送一个请求,它将通过使用这些动词中的一个来指示是哪一类请求,其中最终要的一些动词是GET、POST、PUT和DELETE,这类动词还有其它如HEAD和OPTIONS,但是它们很少用到,所以我们在这篇文章中就不讨论它们了。 

GET

GET是使用最普遍的请求方法,它的作用是从服务器上读取指定的URL。
 
GET请求时只读的,这意味着服务器上的数据是不应该被修改的——服务器应该只是简单的获取未修改的数据。按这种方式,GET请求被认为是安全的操作,因为请求一次或者20次,它的效果都是一样的。
 
此外,GET请求时幂等的,这意思就是你对同一个URL提交多次和提交一次导致的效果应该是一样的,因为一个GET请求只是请求服务器数据,而不去更改服务器上的任何数据。
 
如果GET请求的资源被成功找到,那么响应状态码就是200(OK),如果资源不存在就是400(NOT FOUND)。(当你访问过期的或不存在的URL时,“404页面”就被作为是错误消息)
 
 
 

POST

 POST通常是用来创建新的资源,例如注册表单。但你想创建一些父资源(http://example.com/users)的子资源(如一个新用户),你就可以用POST,你提交的资源是通过URL来识别其父资源,这样服务器在处理这个新资源是就会把它与其父资源联系起来。
 
POST既不是安全的,也不是幂等的。这是因为你对同一个POST请求提交两次或多次,很可能导致创建了两个相同的资源。
 
POST请求响应状态代码201(已创建),并在头部带有指向新创建的资源的链接。 

PUT

PUT通常是用来更新资源的,它是通过URL和请求主体中的信息来识别要更新的资源。PUT也可以被用来创建新的资源。PUT请求也是不安全的操作,因为他们会修改服务器状态,然而,它是幂等的,因为你多次发送对同一个资源的PUT修改请求,它的效果和发送第一次的请求时一样的。
 
如果资源被成功修改,PUT请求响应状态码是200(OK),如果资源不存在则返回404(NOT FOUND)。 

DELETE

DELETE通常是用来删除资源的。DELETE请求也是幂等的,因为你删除一个资源后,即使你多次重复发送多次同一个DELETE请求,结果也是一样的:资源已删除。
 
如果你对同一个资源发送多次DELETE请求,你很可能会得到一个404的错误消息,因为服务器无法找到已被删除的资源。
 
如果成功删除,DELETE请求响应状态码是200(OK),如果删除资源不存在就返回400(NOT FOUND)。
 
对于上面的请求方法,如果服务器处理出错就返回500(服务器内部错误)。 

什么是REST呢?

在我们完成这篇文章前还有最后一个属于:REST没有讲到。
 
你可能之前听说过“REST风格的应用程序”,如果你在客户端与服务器使用HTTP通信的话,那么理解REST到底是什么意思是很重要的,这是遵循REST风格的一个好处。(事实上,我们上面定义的HTTP动词就很大程度上展示了REST是什么。)
 
REST代表“Representational State Transfer”(表述性状态转移),这是一种针对设计应用程序的架构风格。
 
它的基本想法是使用“无状态”,“客户端-服务器”,“可缓存”协议来使两台机器间通信——通常这个协议就是HTTP。这是一种奇特的方式来描述REST,REST给你一系列的约束去设计应用程序,这些约束使得系统性能、扩展性、简单、修改性、可见性、可移植性和可靠性更好。
 
约束的全部内容很长,你可以从这里去了解更多。这篇文章的目的主要是想更深入地探讨以下两个最重要的点:
 
1、接口一致性:这些约束告诉你如何去定义客户端与服务器之间的接口,让你以一种简单、可复制架构的方式去定义,也就是说:
  • 在请求里资源必须是可识别的(比如在URI用资源识别器)。一个资源(比如数据库里的数据)是定义资源表示的数据(如JSON,HTML)。资源和资源表示是分离的——客户端只与资源表示互动。
  • 客户端使用资源表示时必须要有足够的信息去操作服务器上的资源。
  • 客户端与服务器交换的每条消息必须是自我描述的,通过这些信息来决定如何处理这些消息。
  • 客户端必须使用HTTP主体内容、HTTP请求头、查询参数和URL发送状态数据。服务器必须使用HTTP主体内容、响应码和响应头部发送状态数据。
  • 注意:我们上面描述的HTTP动词使得“接口一致性”占据了很重要的部分,因为它们对那些操作的资源呈现一致性。
 
2、无状态:这些约束表示所有状态数据需要处理的客户端请求必须包含在请求本身里(URL,查询参数、HTTP主体,或者HTTP头部),以及服务器发送的所有状态数据需要通过响应内容本身(HTTP头部、状态码和HTTP响应主体)需要返回给客户端。
 
边注:状态或者应用程序状态是服务器完成请求所需要的数据。
 
这就是说对于每一个请求,我们会来回发送状态信息,因此服务器不需要去维护、更新和发送状态。
 
因为有了这种无状态系统使得应用程序更具扩展性,因为在多个请求中,服务器根本不用去操心维护同一会话状态,所有需要获取状态数据都可以在请求和响应本身取得。

结尾语

HTTP很复杂,但正如你所见的,在客户端-服务器关系是一个关键的组成部分。
 
设计REST风格的应用程序至少需要对HTTP有一个基本的了解,有了上面的内容,在你的下一个项目中,关于客户端-服务器通信的神秘之处会有一个更好的理解。
原文地址:https://www.cnblogs.com/Lau7/p/7886727.html