HTTP协议作为网络传输的基本协议,有着广泛的应用。HTTP协议的完整内容很多,但是其核心知识却又简单精炼。学习者应该掌握其基本结构,并且能够举一反三。这篇文章所列的,就是在实际开发中必须知道必须掌握的HTTP知识。

HTTP协议

HTTP协议:消息的分类

HTTP消息(有的文章称之为报文)分为请求消息和响应消息两种基本分类。其中请求消息是客户端发送给服务器的用于请求服务和资源的消息,响应消息是服务器对请求消息的应答。一般来说,一个响应对应一个请求,不多也不少。

HTTP协议:特点

HTTP协议被人总结为无连接无状态的特点:

  1. 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

  2. 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

HTTP协议:消息的基本格式

HTTP协议的请求消息和响应消息的格式及其相似。提炼出它们的共性,可以指出,HTTP消息分为三个部分:

  1. 首行

  2. 头部(Header)

  3. 正文(Body)

其中,头部用来指出HTTP消息的一些属性,它们有固定的格式;正文部分是传输的实际内容,它们的格式是任意的,通常用Content-Type头来指定。首行在请求消息和响应消息中具体格式略有区别,它们表示的按理说应该是HTTP消息最基本的部分。不论是HTTP请求还是HTTP响应,首行都是有的,否则会出现不可饶恕的解析错误;然而头部和正文是可选的,不过实际过程中,多多少少都要包含一些基本的头。

HTTP消息主要是基于ASCII编码的消息实体。主要的意思是指首行和头部都是以ASCII编码,而正文部分的编码就显得任意了。在实际的开发中,发送的文本消息时常会碰到乱码的问题。一种解决办法是,对于文本消息,约定以UTF-8格式进行编码和解码。

知道的人也许知道,HTTP消息是基于TCP协议的上层应用协议。TCP协议是网络流协议的一种。抽象地讲,就是从一台主机一个字节一个字节有序地传输到另一台主机。对于HTTP协议来说,自然保持了这种有序性,即按照首行头部正文的顺序进行传输。首行和头部都是ASCII文本流,正文部分是字节流。一个特殊的控制结构CRLF用来控制每个部分的结束。

CRLF是回车符和换行符的意思,它们是两个特殊的ASCII字符。CR是回车符(\r),在ASCII中的编码是13;LF是换行符(\n),在ASCII中的编码是10.

下面通过一个例子来解释CRLF在HTTP消息中的控制。

GET /simple.html HTTP/1.1<CRLF>     ----- 首行
Accept: text/html<CRLF> --|
Accept-Language: zh-cn<CRLF> |
Accept-Encoding: gzip, deflate<CRLF> |-- 头部
User-Agent: Mozilla/4.0<CRLF> |
Host: localhost:8080<CRLF> |
Connection: Keep-Alive<CRLF> --|
<CRLF> ----- 空白行表示头部的结束
----- 接下来的内容是正文部分

这是一个简单的HTTP请求消息。我在其中做了一些必要的删减,以便每个头足够短都能在一行中显示。记住首行和头部是ASCII流,正文部分是字节流,它们在消息实体中是连续的片段,并不像代码中所示那样有换行的结构。换句话说,原始的消息应该是如下形式:

GET /simple.html HTTP/1.1<CRLF>Accept: text/html<CRLF>Accept-Language: zh-cn<CRLF>Accept-Encoding: gzip, deflate<CRLF>User-Agent: Mozilla/4.0<CRLF>Host: localhost:8080<CRLF>Connection: Keep-Alive<CRLF><CRLF>

回到之前有换行符的代码例子中去。将每个CRLF单独列为一行是便于观察组织。可以清楚地看到,第一行是首行,以CRLF标志其结束;接下来是头部,含有多个消息头,每行定义一个消息头,以CRLF标志其结束;一个单独的CRLF(紧接着上一个CRLF)表示整个头部的结束,接下来是正文部分。在这个示例中,正文部分为空。

另外,可以看到每个消息头的格式都是一致的,即Key:Value的形式。其中Key表示消息头的键,Value表示消息头的值。

HTTP请求

接下来具体讲讲HTTP的请求消息。诚心而论,光是写上面这么点内容就花费了我好久。每每想到写博客耗费的精力和时间,都会影响到我写博客的动力。

之前已经说过,HTTP请求消息也分为三个部分:

  1. 请求行

  2. 请求头部

  3. 请求正文

其中请求头部的格式我们已经见过。请求行的基本格式为:

方法 路径 版本

例如下面的例子:

GET /simple.html HTTP/1.1

就有对应关系:

  • 方法:GET

  • 路径:/simple.html

  • 版本:HTTP/1.1

请求行是HTTP请求消息的最基本要素。版本是用来声明HTTP消息的解析规则,不同的版本在某些地方的表现是不同的,这里不作过多拆解了。现在实际应用中最新的HTTP协议版本就是HTTP/1.1。路径可以理解成该请求消息发往服务器的入口,一般来讲,同一个路径应该代表同一个资源实体。方法表示对该资源实体进行的操作,例如上述的GET方法,其含义就是请求获取该资源的内容。这些都是通常的解释,但不是必然的要求。实际上,服务器会解析到方法和路径,根据方法和路径做出自己相应的响应。这种响应的规则,可以遵循某些规范,也可以完全不考虑这些规范,是任意的。市面上已经存在一些约定俗成的规范了,比如Restful。Restful是非常优秀的基于HTTP协议的WEB API设计理念,很值得讲,但在这里就不讲了。

HTTP请求:方法

首先列出最常用的HTTP方法:

  1. GET

  2. POST

  3. PUT

  4. PATCH

  5. DELETE

  6. HEAD

  7. OPTIONS

之前说过,服务器对于方法的处理,是没有强制的规范的。这句话说得并不全对。其实每个HTTP方法,都是有一些HTTP协议要求的。比如说GET方法请求的资源,浏览器端一般都会有缓存,下次请求的时候可能从缓存中去取就够了,服务器不用再重复发送相同的资源了;但是服务器如果将获取资源的接口的方法定义为POST,那么浏览器端就不会再对资源进行缓存了,即使每次取到的都是同样地内容,都会请求服务器重新发送一遍。所以说,将请求资源的接口的方法定义为POST而不是GET,就是一种不合理的设计。

再比如,GET方法的请求消息是不能定义消息体的,HEAD方法的请求其响应消息是不包含消息体的,这些都是HTTP协议对于HTTP方法的约束。

HTTP请求:路径

方法和路径的组合构成WEB API的入口,路径也是很关键的。路径的基本格式一般是:

basic-path[?query-string]

其中[]中的内容表示可选的。在上例中,basic-path就是/simple.html,但不包含query-string的内容。basic-path形式很像UNIX中绝对路径的样式,要以/打头。单独的/表示一种路径,/a/a/b/a/b/c都是合理的路径表示。不推荐使用/a//a/b//a/b/c/这样/后面不跟任何其他内容的形式(/除外)。优秀的API设计者会利用不同的路径层级来合理地组织资源。

问号后面的部分就是query-string。它的格式是任意的,只要客户端和服务器约定好一定的形式即可。这个部分一般是请求参数的附加。之前说过,GET方法是不包含请求体的,所以GET方法的HTTP请求想要附加参数只能使用这种方式。当然其他方法也是可以使用这种方式附加参数,只要服务器同意就可以了。query-string的格式任意,但在客户端和服务器之间也有预先定好的约定,即键值对的形式。query-string可以表示成一系列键值对的集合,用以下方式表示:

k1=v1&k2=v2&k3=&k4

在这里,&分隔不同的键值对,=表示键和值得关系。可以看到一共有四个键值对关系,它们是:

  • k1: v1

  • k2: v2

  • k3: 空字符串

  • k4: 起码该键被定义了

一般来说,键值对要写成k=v的形式,但是k=和仅仅一个k都是允许的,前者表示键k的值是空字符串,后者表示键k被定义了,但是其值是什么并不关心。

从上面的例子中发现,在query-string中&=被用于特殊的用途了,我们不能再在其中从容地使用这两个符号了。如果我们要在值中包含这两个符号,那咋办呢?方法就是,编码

在实际的HTTP请求中,对于如下的键值关系

k1: &
k2: =

具体的query-string要写成:

k1=%26&k2=%3D

这是因为在ASCII编码中,&的16进制表示是26=的16进制表示是3D。对于需要的编码,就要表示成其实际编码的16进制表示,每个字节都用一个%XX三个字符进行表示。这样,%本身也就要进行编码了,它的编码是%25。除了这些控制字符的编码,还可以进行中文等非英语语言的编码。

对于编码部分,我推荐阮一峰的一篇博文

关于URL编码

虽然看了也未必懂了,但是最起码知道编码不是一件简单的事情。

HTTP请求头

HTTP请求头格式与之前所说的消息头格式没什么两样,就是以冒号分隔的键值对。HTTP请求头中,既包含预定义的头(如Content-Type、Content-Length等),也支持自定义头。原本打算多列出几个常见的请求头的,但限于精力,不打算这样做了。我只说说我最常用的Content-Type头吧。

Content-Type头,既可用于请求消息,也可用于响应消息,是规定请求正文内容格式的头部。例如利用这个头部,我们可以规定正文的格式为纯文本格式、表单格式、XML格式、JSON格式、图像格式等。例如Content-Type: application/json就表示JSON文本格式。

在小节的末尾,我良心地给出一个关于HTTP预定义头的参考网址:

HTTP消息头大全

HTTP响应

HTTP响应消息的基本格式也是一样的,包含三个部分:

  1. 响应行

  2. 响应头部

  3. 响应正文

响应头部和响应正文我觉得不需要再多说了。响应行的基本格式是:

版本号 状态码 状态文本

例如下面的响应行:

HTTP/1.1 200 OK

其对应关系为:

  • 版本号:HTTP/1.1

  • 状态码:200

  • 状态文本:OK

HTTP状态码主要表示应答的状态。状态码是由3个数字表示,其中第一个数字表示一个大状态,后面两个数字表示该大状态的一个子状态。200就表示操作成功,还有其他常见的如404表示对象未找到,500表示服务器错误,403表示不能浏览目录等等。

状态码一共分为五个大状态,它们是:

  • 1xx

  • 2xx:请求成功处理

  • 3xx

  • 4xx:客户端出错

  • 5xx:服务器出错

HTTP状态码大全

HTTP协议示例:

接下来的所有示例中,我们将代码都写成前面的一行一行的模式,但略去. 这时只要记住每行的结尾都暗含一个CRLF控制就可以了。例如:

GET /simple.html?bg=white HTTP/1.1
Accept: text/html
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0
Host: localhost:8080
Connection: Keep-Alive

GET请求没有请求正文,但可以包含query-string.

POST请求可以包含请求正文,例如下面带JSON格式正文的POST请求:

POST /test/demo_form.asp HTTP/1.1
Host: w3schools.com
Content-Type: application/json
Content-Length: 38 {"name1": "value1", "name2": "value2"}

一个返回404错误的响应示例:

HTTP/1.1 404 Not Found
Date: Mon, 06 Mar 2006 09:03:14 GMT
Server: Apache/2.0.55 (Unix) PHP/5.0.5
Content-Length: 291
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /notexist was not found on this server.</p>
<hr>
<address>Apache/2.0.55 (Unix) PHP/5.0.5 Server at localhost Port 8080</address>
</body></html>

HTTP必知必会的更多相关文章

  1. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  2. 读书笔记--SQL必知必会--建立练习环境

    书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL in 10 Minutes - Fourth Edition> MyS ...

  3. 读书笔记--SQL必知必会12--联结表

    12.1 联结 联结(join),利用SQL的SELECT在数据查询的执行中联结表. 12.1.1 关系表 关系数据库中,关系表的设计是把信息分解成多个表,一类数据一个表,各表通过某些共同的值互相关联 ...

  4. 读书笔记--SQL必知必会18--视图

    读书笔记--SQL必知必会18--视图 18.1 视图 视图是虚拟的表,只包含使用时动态检索数据的查询. 也就是说作为视图,它不包含任何列和数据,包含的是一个查询. 18.1.1 为什么使用视图 重用 ...

  5. 《MySQL 必知必会》读书总结

    这是 <MySQL 必知必会> 的读书总结.也是自己整理的常用操作的参考手册. 使用 MySQL 连接到 MySQL shell>mysql -u root -p Enter pas ...

  6. 《SQL必知必会》学习笔记(一)

    这两天看了<SQL必知必会>第四版这本书,并照着书上做了不少实验,也对以前的概念有得新的认识,也发现以前自己有得地方理解错了.我采用的数据库是SQL Server2012.数据库中有一张比 ...

  7. SQL 必知必会

    本文介绍基本的 SQL 语句,包括查询.过滤.排序.分组.联结.视图.插入数据.创建操纵表等.入门系列,不足颇多,望诸君指点. 注意本文某些例子只能在特定的DBMS中实现(有的已标明,有的未标明),不 ...

  8. .NET程序员项目开发必知必会—Dev环境中的集成测试用例执行时上下文环境检查(实战)

    Microsoft.NET 解决方案,项目开发必知必会. 从这篇文章开始我将分享一系列我认为在实际工作中很有必要的一些.NET项目开发的核心技术点,所以我称为必知必会.尽管这一系列是使用.NET/C# ...

  9. 0005 《SQL必知必会》笔记01-SELECT语句

    1.SELECT基本语句: SELECT 字段名1,···,字段名n FROM 表名 2.检索所有字段,用"*"替换字段名,这会导致效率低下 SELECT * FROM 表名; 3 ...

  10. 2015 前端[JS]工程师必知必会

    2015 前端[JS]工程师必知必会 本文摘自:http://zhuanlan.zhihu.com/FrontendMagazine/20002850 ,因为好东东西暂时没看懂,所以暂时保留下来,供以 ...

随机推荐

  1. [.net 面向对象编程基础] (16) 接口

    [.net 面向对象编程基础] (16) 接口 关于“接口”一词,跟我们平常看到的电脑的硬件“接口”意义上是差不多的.拿一台电脑来说,我们从外面,可以看到他的USB接口,COM接口等,那么这些接口的目 ...

  2. mac下apache配置,解决It is not safe to rely on the system's timezone settings.

    之前一直转windows平台下做php,很少遇到问题.现在有了macbook,还在慢慢的熟悉中,搭建php开发环境,熟悉mac系统文档组织还有命令,颇费功夫. 今天我在mac下做一个php的练习,用到 ...

  3. 爱上MVC3~在控制器或Action上动态设定模板页(Layout)

    回到目录 很多境况下,我们需要设置自己模块的layout,即它的布局页面,在MVC2中叫它模板页面,你可以在return view方法时设置它,当然,这不是一种好方法,因为我不想每个action都去设 ...

  4. CSS3常用属性

    CSS是我们常用的控制网页样式和布局的一种标准. CSS3是最新的CSS标准. CSS3被拆分为"模块",旧的规范也已经拆分为小的块,同时还增加了新的属性. 一些比较重要的CSS3 ...

  5. vagrant homestead laravel 编程环境搭建

    这里面其实坑不少的,首先介绍 VirtualBox  虚拟机,windows下安装linux必须用的一个工具 vagrant 封装虚拟机的一个软件,可以设置好系统,安装好软件,什么时候用,直接导入就行 ...

  6. MyBatis 环境搭建 (一)

    一.MyBatis简介 MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索.MyBatis 使用简 ...

  7. DataGridView的Cell事件的先后触发顺序

    最近正在使用“DataGridView”对一个旧的Vs 2003开发的WINDOWS应用程序进行改造. 发现Vs 2003中的"DataGrid"中的一些事件已经在新的控件Data ...

  8. Model-View-Controller(MVC) is an architectural pattern that frequently used in web applications. Which of the following statement(s) is(are) correct?

    Model-View-Controller(MVC) is an architectural pattern that frequently used in web applications. Whi ...

  9. Redis基础介绍及安装示例

    1.基本概念 Redis是由Salvatore Sanfilippo(意大利)开发的一个开源的高性能键值存储数据库,于2009年发布第一个版本并与同一年开源,官方站点:http://www.redis ...

  10. 信息加密之非对称加密算法RSA

    前面为大家已经总结了,基于密钥交换的DH算法,现在就为大家再介绍一种基于因子分解的RSA算法,这种加密算法有两种实现形式:1.公钥加密,私钥解密:2.私钥加密,公钥解密.下面就为大家分析一下实现代码, ...