无论从事前端还是后端开发,我们都应该了解HTTP,HTTP的知识体系庞大而复杂,可能用几篇博客都无法完全覆盖,所以本篇只对实际应用所能涉及到的知识进行介绍。
什么是HTTP
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。--来源:百度百科
基于官方的解释在百度上可以搜到很多,这里不再赘述。重点在于理解它是一种通讯协议,HTTP定义了一种规约,网络上的各种终端基于这种规约,可以进行跨地域,跨技术平台的通讯。
Url
我们知道,想要访问一个网站,需要在浏览器地址栏中输入一串Url,如,我们要访问简书//www.greatytc.com/。
点击回车,稍等片刻便可以看到丰富多彩的页面,整个过程实际上是由浏览器向后台服务器发送了一个HTTP请求。服务器收到请求进行相应处理后生成一个响应,随后返回至浏览器,经过浏览器解析呈现信息内容。
HTTP通过Url(统一资源定位符)建立连接和传输数据,Url标识网络上某一处资源的地址,我们以一个常见的GET请求为例,看看其构成。
- 协议部分:访问服务器所使用的协议,如http,https,ftp等;
- 域名部分:目标主机的域名,本例中域名是“www.process.com”,也可以使用IP地址。通过域名,可以帮助你在浩瀚的网络世界中快速定位你想访问的目标服务器;
- 资源路径:域名“/”后面的部分,又称虚拟目录。指向是你要访问的目标服务器下某个资源的路径;
- 访问参数:“?”后面的部分是访问参数,多个参数间使用“&”符连接。
在初步了解Url之后,我们一起来揭开HTTP的神秘面纱。
互联网中,无时不刻不在进行着数据的交换与传输,这些传输以报文的形式进行。报文包含了一次传输所需要的所有信息。之前提到,HTTP是一种通讯协议,报文格式就是协议中的一部分。两端只要遵从相同的协议,就可以进行通讯。
Request请求报文
为了更直观的理解,我用Chrome浏览器自带的抓包工具,抓取一次Request请求,且看下图:
可以抽象为以下图表结构:
-
请求行
包含以下三个部分- 请求方法: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请求时,字符串则会被放入请求体,如下图:
文件分割
某些场景下,提交的表单数据可能包括文件,这时可以将enctype
设置为multipart/form-data,用于上传文件流,浏览器会按form表单每个字段或文件将请求体分割成多个部分。请求头中Content-Type的属性值为multipart/form-data; boundary={boundary},{}中为定义的内容分隔符。如Content-Type: multipart/form-data; boundary=----hSJb4uI9kw0Snmu9dw
,接下来我们看报文结构:
可以看到,请求体中包含一个名为“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,需要持续投入时间和精力,本文涉猎的每一个知识点,都可以继续展开。同时,无论你是两眼发蒙的职场鲜肉,还是记忆等待唤醒的研发老司机,笔者都希望能够从中有所收获。