爱客仕-前端团队博客园

http学习笔记(上)

很早之前看了这本日系技术书《图解http》,觉得有所收获。稍微整理了下相关的知识点,这里是第一部分,关于请求方法与常用状态码。

http请求报文与响应报文

请求报文和响应报文都由报文头部、空行和报文主体三部分组成。

其中请求报文头部分为请求行和头部字段。请求行中包含请求的方法、请求地址和请求所使用的协议。

请求头

响应报文头部分为状态行和头部字段。状态行中包含协议版本、状态码和原因短语。

响应头

其实头部字段还可以细分为通用头部字段、请求/响应头部字段、实体头部字段和其他(非标准内定义的头部字段)。当然这些细分都不是重点。

http请求方式

方法 说明 支持的协议版本
GET 获取资源 1.0/1.1
POST 传输实体类型 1.0/1.1
PUT 传输文件 1.0/1.1
HEAD 获得报文头部 1.0/1.1
DELETE 删除文件 1.0/1.1
OPTIONS 询问支持的方法 1.1
TRACE 追踪路径 1.1
CONNECT 要求用隧道协议连接代理 1.1
Link 建立和资源之间的联系 1.0
UNLINK 断开连接关系 1.0

幂等、副作用与请求参数

相较于http1.0,http1.1新增了一些方法,也废除了一些方法。我们比较常用的依旧是http1.0中就有的这4种方法:get,post,put,del。

关于get,post,put,del的区别,我们可以从三个方面考虑:

  • 幂等(通常这点是最重要的)

所谓幂等就是请求提交1次与请求提交n次,相应资源的状态没有区别。put、delete、get都是幂等,而post为非幂等,比如新增数据的请求发送多次会创建多个相同的数据。

  • 副作用

我曾经把副作用和幂等混为一谈,其实它们是很不一样的。副作用关注的是这个请求发送前与发送后,响应资源的状态有没有发生改变。put,delete,post分别为更新、删除和提交,状态发生了变化,它们是有副作用的,而get不变,没有副作用。

  • 请求参数
    请求时传递参数有两种方式,url中的Query String和请求体。但get和delete并不支持请求体,而post和put是支持的。post和put是支持的,对于get和delete,尽管标准中没有规定它是否支持,一些服务器在实现的时候可能不支持传请求体。(4.3.1 get,4.3.2 head也有类似的描述)

A payload within a DELETE request message has no defined semantics;sending a payload body on a DELETE request might cause some existing implementations to reject the request. RFC 7231

stackoverflow上关于delete请求是否允许传请求体的讨论

其他方法

  • head:它经常用来检测资源(是否过期、是否存在),head不返回报文主体,相较于get而言会更快。我们也可以利用head获取服务器时间,因为响应返回的时候响应头中带有Date字段。

  • trace:它的应用场景比如:在路由排错时,结合Max-Forwards使用。

http状态码

我们可以把http状态码分为以下五个类别:

类别 说明
1XX 请求正在处理
2XX 请求成功
3XX 重定向
4XX 客户端错误
5XX 服务端错误

常用状态码

一、1XX

1、101 Switching Protocols,表示服务器将遵从客户的请求切换协议。场景,比如websocket协议。

二、2XX

1、200 OK 请求正常返回

这个最常见,不多解释了。

2、204 No Content ,这个状态表示服务器已经成功处理请求,但是返回的响应报文中不含有实体主体,也不允许返回实体主体。
场景,比如上传一个已经存在的资源,服务器返回204。

上传已经存在的图片

3、206 Partial Content 返回部分内容。客户端只请求了资源的部分内容。

场景,在未禁用缓存的情况下,前一个资源还未请求完就终止,此时再次请求该资源。如果服务器支持按范围请求(Accept-Ranges:bytes)的话。

返回部分内容

三、3XX

3XX基本上都与重定向有关,比如301 Moved Permanently永久重定向,302 Found临时重定向,303 See Other 临时重定向,307 Temporary Redirect临时重定向。
重定向状态码总是结合着响应头的Location字段使用。

而304 Not Modifield 这个状态比较奇葩,它是属于缓存相关(下篇文章会讲304与那些缓存相关字段)。

可能很多小伙伴都会对302,303,307这三个临时重定向的状态码感到一脸懵逼。我们可以看下RFC2616中的这段话:

Note: RFC 1945 and RFC 2068 specify that the client is not allowed to change the method on the redirected request. However, most existing user agent implementations treat 302 as if it were a 303 response, performing a GET on the Location field-value regardless of the original request method. The status codes 303 and 307 have been added for servers that wish to make unambiguously clear which kind of reaction is expected of the client.

大致意思是尽管标准禁止重定向时修改method,大多数现有浏览器在实现的时候,还是会将302当成303处理(在规范中,客户端发出post请求后,如果收到302状态码,是不允许自动发送重复的post请求的,因为post非幂等,但很多浏览器在这种情况下将post改成了get,获取location字段信息,重新发起请求),规范后来为此专门引入了303和307。303明确表示客户端应该用get方式去获取资源,而307不会从post变成get(307其实就是1.0中的302)。

Note: For historical reasons, a user agent MAY change the request method from POST to GET for the subsequent request.If this behavior is undesired, the 307 (Temporary Redirect) status code can be used instead. RFC7231 6.4.2与6.4.3

所以说,303和307是标准发现浏览器的302实现不合规范后,从302中细分出来的,然而令人尴尬的是,尽管标准已经出来了,303和307依旧比较冷门,即便使用也依旧没有遵循规范。我们比较常见的还是301和302吧。
301是搜索引擎在抓取新的内容后也会把url地址替换成新的。302重定向搜索引擎会抓取新的内容而保留旧的网址,这可能会被搜索引擎认为是在作弊,也有可能被一些站长用来做网址劫持。对用户而言,我们感受不到区别。

example1:301

301状态码

example2:302

302状态码

example3:307

307状态码

(303的例子我没找到)

四、4XX

1、400 Bad Request ,表示请求报文中存在语法错误

2、401 Unauthorized,该状态码表情请求需要通过http认证,比如身份认证过期或未登录。

3、403 Forbidden 请求的资源访问被服务器拒绝

4、404 Not Found 资源不存在

5、405 Method Not Allowed,方法未允许,这个在联调时可能会遇到。

5、408 Request Timeout,请求超时

6、410 Gone,请求资源已删除。它与404的区别是410知道文件已经被删除,404是未知原因无法找到。

五、5XX

1、500 Internal Server Error,服务端在执行请求时报错

2、502 Bad Gateway,网关错误

3、503 Service Unavailable,负载过高,服务器无法响应。这种通常过段时间就会正常。

4、504 Gateway Time-out,网关超时