阅读 960

图文并茂!深入了解HTTP,你离入门,可能还差这一篇



无论从事前端还是后端开发,我们都应该了解HTTP,HTTP的知识体系庞大而复杂,可能用几篇博客都无法完全覆盖,所以本篇只对实际应用所能涉及到的知识进行介绍。

什么是HTTP

超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。--来源:百度百科

基于官方的解释在百度上可以搜到很多,这里不再赘述。重点在于理解它是一种通讯协议,HTTP定义了一种规约,网络上的各种终端基于这种规约,可以进行跨地域,跨技术平台的通讯。

Url

我们知道,想要访问一个网站,需要在浏览器地址栏中输入一串Url,如,我们要访问简书www.jianshu.com/
点击回车,稍等片刻便可以看到丰富多彩的页面,整个过程实际上是由浏览器向后台服务器发送了一个HTTP请求。服务器收到请求进行相应处理后生成一个响应,随后返回至浏览器,经过浏览器解析呈现信息内容。



HTTP通过Url(统一资源定位符)建立连接和传输数据,Url标识网络上某一处资源的地址,我们以一个常见的GET请求为例,看看其构成。
Url结构示例
Url结构示例
  • 协议部分:访问服务器所使用的协议,如http,https,ftp等;
  • 域名部分:目标主机的域名,本例中域名是“www.process.com”,也可以使用IP地址。通过域名,可以帮助你在浩瀚的网络世界中快速定位你想访问的目标服务器;
  • 资源路径:域名“/”后面的部分,又称虚拟目录。指向是你要访问的目标服务器下某个资源的路径;
  • 访问参数:“?”后面的部分是访问参数,多个参数间使用“&”符连接。

在初步了解Url之后,我们一起来揭开HTTP的神秘面纱。 互联网中,无时不刻不在进行着数据的交换与传输,这些传输以报文的形式进行。报文包含了一次传输所需要的所有信息。之前提到,HTTP是一种通讯协议,报文格式就是协议中的一部分。两端只要遵从相同的协议,就可以进行通讯。

Request请求报文

为了更直观的理解,我用Chrome浏览器自带的抓包工具,抓取一次Request请求,且看下图:


抓取Rquest请求
抓取Rquest请求

可以抽象为以下图表结构:


Rquest请求报文
Rquest请求报文
  • 请求行
    包含以下三个部分
    • 请求方法:HTTP/1.1协议定义了8种请求方法 GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE。其中,GET、POST最为常用。在主流的Restful架构风格中,常用GET表示获取资源,POST表示新建或更新资源,PUT表示更新资源,DELETE表示删除资源。
    • 请求地址:请求目标资源的访问地址,同Url。
    • 协议版本:注明HTTP协议的版本,本例中使用的是HTTP1.1版本。
  • 请求头
    以键值对的形式,注明向服务器发起请求的附加信息。(ps:关于请求头Header,后面我会专门介绍)
  • 空行
    请求头与请求体中的空行是必须存在的,即便第四部分请求体中没有数据。
  • 请求体
    可用于存放媒体数据,通过请求头中Content-Type属性设置媒体类型信息,可以是HTML,图片,JSON字符串等,本例的请求体中没有数据。

Response响应报文

上文提到,当服务器对接收到的请求进行处理后,会生成一个响应信息返回到浏览器。下面我们来看看响应报文什么样:




同样可以抽象出如下图表结构:




响应报文除了第一行与请求报文不同,其余部分格式一致。所以只对Response响应报文的第一行“状态行”进行说明。
状态行分为协议版本,响应码,响应信息三个部分:
  • 协议版本:概念与请求行中的一致,用于注明HTTP协议的版本。
  • 响应码:每次请求目标服务器,该目标服务器都会返回一个带有状态码的头文件。比如,在访问信息正常的情况下,服务器会返回200。另外还有我们常见的404状态码。(传送门:点我了解更多状态码信息
  • 响应信息:包含服务器返回的响应信息,本例中因为正常访问,响应信息是“OK”。

HTTP Header

无论是请求还是响应,客户端和服务器之间都需要传递附加信息,Header部分作为载体承载这些信息。Header中属性的格式为 属性名: 属性值(注意!冒号后带空格),如:

Content-Type: text/plain    
Cache-Control: no-cache
复制代码

以下是Header中常见属性:

常见请求头

常见响应头


通俗的讲,这些属性主要用于“带话儿”,在请求时告知服务器,传输的内容的长度,格式,访问者身份信息等,以便进行安全保障。实际上请求头和响应头有很多通用属性,这里不一一列举。(更多内容可以点击:HTTP 头域大全)。

HTTP Entity

请求体可以存放各种媒体类型的数据,根据使用场景不同,请求体的形式也不同,常用的有以下三种

表单提交

我们在提交表单时,form表单的enctype参数指定了HTTP请求的Content-Type,默认情况下enctype = application/x-www-form-urlencoded,如

<form action="/upload" method="post" enctype="application/x-www-form-urlencoded">
  <input type="text" name="param1">
  <input type="text" name="param2">
  <input type="file" name="file">
</form>
复制代码

请求头中Content-Type: application/x-www-form-urlencoded,浏览器会以x-www-form-urlencoded方式将form表单数据格式化为key1=value1&key2=value2...形式的字符串。如果使用GET请求,字符串会被用“?”拼接到Url后作为QueryString,使用POST请求时,字符串则会被放入请求体,如下图:

POST 请求Form表单提交
POST 请求Form表单提交
文件分割

某些场景下,提交的表单数据可能包括文件,这时可以将enctype设置为multipart/form-data,用于上传文件流,浏览器会按form表单每个字段或文件将请求体分割成多个部分。请求头中Content-Type的属性值为multipart/form-data; boundary={boundary},{}中为定义的内容分隔符。如Content-Type: multipart/form-data; boundary=----hSJb4uI9kw0Snmu9dw,接下来我们看报文结构:

multipart上传
multipart上传

可以看到,请求体中包含一个名为“name”的字段和一个名为hello的txt文件,中间以--{boundary}分割,报文结尾处以“--{boundary}”在加上“--”标注表示结束。 上面提到两种 POST 数据方式,不仅受到原生浏览器支持,服务器也能够良好支持。不过在移动互联网大前端时代,我们可能需要通过更灵活的方式面对复杂的数据结构。

自定类型

在移动开发的场景下,移动端在向服务器传输数据时,可以将数据Bean转化成Json字符串,放入请求体中,以安卓开发时使用retrofit2网络框架请求为例:

//创建参数Bean,设置参数        
Param param = new Param();
param.setParam1(param1);
param.setParam2(param2);
param.setParam3(param3);
Gson gson = new Gson();
//转化Json字符串
String paramStr = gson.toJson(param)
//设置实体Content-Type,将Json字符串放入实体
RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),paramStr);
//发起请求
Observable<DataBean> response = api.sendRequest(body);
复制代码

最终发送的请求就是

POST http://www.process.com HTTP/1.1 
Content-Type: application/json;charset=utf-8  
~ ~ ~ ~ ~ ~ ~ ~ ~ 空行 ~ ~ ~ ~ ~ ~ ~ ~~ ~
{"param1":"abc","param2":"def","param3":"ghk"}
复制代码

使用Json可以应对复杂的结构化数据,自定类型除使用Json外,还可以通过将Content-Type属性设置为application/xml,application/zip,来存放更多媒体类型。

HTTP RequestMethod

无论是请求报文还是响应报文,头行格式中都有请求方法属性。在实际项目中,初学者页时常搞不清楚这么多请求方法的区别。先列出8种方法在网上的主流描述,便于直观了解:

序号 方法名 解释
1 GET 请求指定的页面信息,并返回实体主体。
2 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
3 PUT 从客户端向服务器传送的数据取代指定的文档的内容。
4 DELETE 请求服务器删除指定的页面。
5 PATCH 实体中包含一个表,表中说明与该URI所表示的原内容的区别。
6 OPTIONS 允许客户端查看服务器的性能。
7 HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头。
8 TRACE 回显服务器收到的请求,主要用于测试或诊断。

在RESTful风格架构盛行之前,我们最多用到的是GET和POST,GET执行简单效率高,但由于GET采用明文拼接请求参数,固安全性较低。POST请求将参数放入实体,相对提高了信息窃取的门槛。另外GET请求会受到Url长度限制,无法应对复杂的数据结构。POST请求则无此问题。
在RESTful风格中,GET,POST,PUT,DELETE,分别被抽象出来对应查,增,改,删四项操作。
至此,本篇内容基本完毕。想深入了解HTTP,需要持续投入时间和精力,本文涉猎的每一个知识点,都可以继续展开。同时,无论你是两眼发蒙的职场鲜肉,还是记忆等待唤醒的研发老司机,笔者都希望能够从中有所收获。

文章分类
前端
文章标签