HTTP协议

Posted March On

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HTTP协议相关的知识,希望对你有一定的参考价值。

1 发展脉络

1.1、1991 HTTP/0.9

  1. 建立TCP连接、客户端发送请求(只有GET命令)、服务端返回请求(只能返回html格式字符串)后就关闭TCP连接

1.2、1996.5 HTTP/1.0

  1. 请求命令:增加 POST、HEAD命令;任何格式的内容都可以发送(文字、图像、视频、二进制文件等);HTTP请求和回应的格式中加入了头信息(HTTP header)用于描述一些元数据(如Content-Type等)。
  2. 主要缺点:每个TCP连接只能发送一个请求,发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。有些浏览器借助 Connection: keep-alive 请求头要求服务端不关闭TCP,服务端同样回复此字段,从而达到TCP复用,直到客户端或服务器主动关闭连接。但此字段在此版本中不是标准字段。

1.3、1997.1 HTTP/1.1

  1. 请求命令:增加 PUT、PATCH、HEAD、 OPTIONS、DELETE
  2. 最大变化:引入了持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive。 客户端和服务器发现对方一段时间没有活动就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送 Connection: close ,明确要求服务器关闭TCP连接。 目前,对于同一个域名,大多数浏览器允许同时建立6个持久连接。
  3. 管道机制:在同一个TCP连接里面,客户端可以同时发送多个请求
  4. Content-Length 字段:因一个TCP连接现可传送多个回应,因此借助此字段区分数据包是属于哪一个回应的。
  5. Transfer-Encoding字段:使用Content-Length字段的前提是服务器发送回应前必须知道回应的数据长度。对于一些很耗时的动态操作来说,这意味着服务器要等到所有操作完成才能发送数据,显然这样的效率不高。此时可不使用Content-Length字段,而借助 Transfer-Encoding: chunked 产生一块数据,就发送一块。
  6. Host字段:客户端请求的头信息新增了Host字段,用来指定服务器的域名。有了Host字段,就可以将请求发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础。
  7. 主要缺点:虽然1.1版允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为"队头堵塞"(Head-of-line blocking)。

1.4、2009 SPDY

  1. 由Google研制,主要解决 HTTP/1.1 效率不高的问题。 此协议在Chrome浏览器上证明可行以后,就被当作 HTTP/2 的基础,主要特性都在 HTTP/2 之中得到继承。

1.5、2015 HTTP/2

  1. 二进制协议:是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。(HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本、图片等各自格式数据)
  2. 多工(Multiplexing):HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞",实现了双向实时通信。
  3. 头信息压缩机制(header compression):HTTP 协议不带状态,每次请求都必须附上所有信息使得请求的很多字段都是重复的,浪费带宽影响速度。HTTP/2引入压缩机制,一方面,头信息使用gzip或compress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段而只发送索引号,这样就提高速度了。
  4. 服务器推送(server push):HTTP/2 允许服务器未经请求,主动向客户端发送资源。

 

总结下,发展过程主要围绕持久连接、连接复用、数据分块传输、丰富类型支持 等方面展开。
题外话:OPTIONS方法哪里被使用到?如CORS中浏览器在正式发请求前会先发个OPTION请求去询问服务器是否允许接下来的跨域请求。

 

2、HTTP协议(HTTP/1.1)

(详见:HTTP教程

2.1、消息格式

1、请求消息(四部分):

请求行(请求方法、请求路径、协议版本)

请求头(键值对列表,一个键值对一行)

回车换行

请求数据

注:HTTP 1.0规定,请求头的key、value都只能是ascll字符

 

2、响应消息(四部分):

状态行或响应行(协议版本、状态码、状态说明)

消息报头(键值对列表,一个键值对一行)

回车换行

响应正文

 

2.2、请求方法

各方法的具体作用可以参阅javax.servlet.http.HTTPServlet类的方法说明。

总结:

    • GET:无副作用,幂等,不可带 Request Body
    • PUT:副作用,幂等,可以带 Request Body
    • POST:副作用,非幂等,可以带 Request Body
    • DELETE:副作用,幂等,不可带 Request Body

注:

1、GET与POST的区别

2、使用POST还是PUT(详情参考:REST简介):综合考虑 资源ID生成幂等性是否将创建和更新合并在一个操作 三点

个人理解,选择的标准在于操作是否是幂等的,所谓幂等,即多次操作所造成的结果(side effect,译为副作用,感觉很别扭) 是否一样,若一样则用put,否则用post。

注意这里的side effect不是指请求得到的结果,而是造成的结果。因此GET、DELETE、HEAD等都是幂等的,而POST不是。由于PUT操作应符合幂等性,所以其应用于资源更新时,请求者应该指定资源的所有字段,若只有更新部分字段则应用POST。

 3、OPTIONS请求的使用场景:CORS中与目标服务器的跨域协商用的是OPTIONS,具体可参阅:浏览器同源策略与CORS - MarchOn

 

2.3、状态码

(详见:HTTP状态码,更权威的见 RFC定义

几个典型状态码:

200:请求成功,一般用于GET与POST请求。

204:No Content。表示该请求已经成功了,但客户端客户不需要离开当前页面。默认情况下 204 响应是可缓存的,一个 ETag 标头包含在此类响应中。 使用示例:可借此防止form表单跳转

206:断点续传

300:多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择。

301:永久的请求重定向,表示请求的资源已被永久移动到新URI。返回的location字段指定新URI,浏览器会自动重定向到新URI(一次访问对应两次服务器请求),地址栏的地址也会变。浏览器会缓存新URI,除非缓存失效,否则今后任何向旧URI的请求浏览器都会在发起请求前读取缓存并直接向新URI发起(即一次访问对应一次服务器请求)。

注:带\'location\' response header的重定向需要目标服务器配置CORS白名单才能成功重定向到目标站点,否则会被browser同源策略限制重定向。故提供自定义header让前端配合进行重定向。下同。

302:临时请求重定向。与301类似,浏览器也会自动重定向到新URI。与301的区别:地址栏的地址不变;不缓存新URI,故每次访问会对应两次服务器请求。

303:查看其它地址。与301类似,使用GET和POST请求查看。

304:未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源,客户端收到此响应码后会从本地缓存取资源。

305:使用代理。所请求的资源必须通过代理访问。

307:临时的请求转发。与302类似,用于GET请求重定向,302与307的区别在于:前者由浏览器完成;后者由服务端完成,由服务端进行请求转发,对前端来说相当于是透明的、反向代理。

400:坏请求。客户端请求的语法有误,服务端无法理解。

401:未认证。请求要求用户的身份认证。

402:Payment Required

403:未授权,禁止访问。服务端理解客户端的请求,但拒绝执行请求。

404:Not Found。

405:Method Not Allowed

408:请求超时。服务端等待客户端发送的请求时间过长,超时。

410:gone,表示资源已经永久删除,不可用了。资源标记为过时(301)一段时间后,通过此状态码告知客户端资源已永久移除。通常是管理员认为设置的,若不清楚是否永久移除,则用404。

416:Range Not Satisfied,断点续传时请求的范围越界时返回此状态码

500:服务器内部错误,无法完成请求。

501:服务端不支持请求的功能,无法完成请求。如若服务器不支持除上述GET、POST等方法外的请求方法,则返回501。可参阅javax.servlet.http.HttpServlet#service方法的逻辑。

502:Bad Gateway。充当网格或代理的服务器从远程服务器接收到了一个无效请求。

504:Gateway Timeout。充当网关或代理服务器未及时从远端服务器获取请求。

505:服务端HTTP版本不支持,无法完成请求。

重定向相关:301、302、307 。需要注意:

307是服务端的操作,对浏览器和前端开发者来说是透明的;

301、302时若response的"Location" header有值,则浏览器会自动进行重定向,前端开发者并无法干预:此时即使js代码有针对status==302的判断也不会走这段js逻辑,因为浏览器发现Location有值时就进行重定向了,这先于开发者的js逻辑执行。可见,这种重定向通常是服务端发起的指令,开发者干预不了。

前端重定向:前端开发者通过js代码(window.location="xxx")进行重定向。上述第二种除非目标站点将请求来源站点添加到其CORS白名单,否则请求会受到浏览器的同源限制,从而重定向失败,此时可改用前端重定向方案——服务端将重定向目标地址放到自定义的其他response header而非"Location",前端js判断是301/302时候,取该header的值并跳转过去。

断点续传相关:206、416

HTTP协议中的请求路径格式为: 协议://主机:端口/相对地址?参数#Hash ,其中若端口是80则可以默认不写。如 http://www.cnblogs.com/z-sm/p/6243378.html#blogTitle3 

scheme://host[:port#]/path/.../[?query-string][#anchor]
scheme         指定底层使用的协议(例如:http, https, ftp)
host           HTTP服务器的IP地址或者域名
port#          HTTP服务器的默认端口是80,这种情况下端口号可以省略。如果使用了别的端口,必须指明,例如 http://www.cnblogs.com:8080/
path           访问资源的路径
query-string   发送给http服务器的数据
anchor         锚

 


2.4、主要请求头或响应头

Content-Type:响应头,表示响应的数据类型

(http主要 MediaType)

Java里通过 request.getServletContext().getMimeType(fileName) 可获取到。

HTTP缓存相关的请求头和响应头:Date、Cache-Control、Last-Modified、Etag、If-Modified-Since、If-None-Match、Pragma

相关状态码:200、304

用法详见:https://www.cnblogs.com/z-sm/p/10246261.html

Content-Length:响应头,表示数据长度。

在未启用分块传输时,服务器会缓存指定大小的数据后才发送给浏览器、浏览器会根据该值来确定数据是否接收完毕,若设得比实际内容小,则浏览器显示的内容会截断、若大则会处于pending状态。

Content-Encoding:响应头,表示返回的数据的压缩方式,如gzip。

浏览器收到数据时会用该响应头指定的压缩方式对数据解压。

Transfer-Encoding:响应头,表示内容的传输方式。

常用的是chunked,表示分块传输,在数据量很大,并且在请求未能完全处理完成之前无法知晓响应的体积大小的情况下非常有用。在这种传输方式下,服务器不再数据缓存完才发送,而是会直接把数据发送给客户端而无需进行缓冲或确定响应的精确大小——后者会增加延迟。此外,这种传输方式允许服务器在最后发送响应头(非此方式下是不允许的)。

主要使用场景:在要传输大量的数据,但是在请求在没有被处理完之前响应的长度是无法获得的。例如,当需要用从数据库中查询获得的数据生成一个大的HTML表格的时候,或者需要传输大量的图片的时候。具体可参阅:https://www.cnblogs.com/z-sm/p/5478495.htmlhttps://zh.wikipedia.org/wiki/%E5%88%86%E5%9D%97%E4%BC%A0%E8%BE%93%E7%BC%96%E7%A0%81

服务端在设置了Transfer-Encoding为chunked后会忽略content-length设置(即后者不再设置到响应头)

范围传输(断点续传)相关请求头和响应头:Range、If-Range、Accept-Ranges、Content-Range等。可和分块传输一起使用。

相关状态码:200、206、416

用法详见:xxx

Security Related HTTP Response Headers:(参阅:https://docs.spring.io/spring-security/site/docs/5.3.4.RELEASE/reference/html5/#headers

X-Content-Type-Options:nosniff。响应头,服务端用它指示客户端(浏览器)不可修改响应的Content-Type类型,也就是不要根据文件内容来推断MIME类型覆盖响应的值,否则内容嗅探可能会把不可置信的MIME类型转变为可执行的MIME类型,带来安全隐患。只用于script、style两种类型的响应。

X-Frame-Options:响应头,用来指定当前站点是否允许被作为iframe嵌入在其他页面,以防御点击挟持(clickjacking)。取值:

deny

sameorigin

allow-from https://example.com

X-XSS-Protection 

Strict-Transport-Security

Content-Security-Policy

Content-Security-Policy-Report-Only

Referrer-Policy

Feature-Policy

Clear-Site-Data

Host、Origin、Referer都是发起请求时request中的一种header,区别:

Host:用来描述请求将被发送的目的地。值包括且仅包括域名和端口号;所有类型的request中都会包含此header信息。如: Host: static.cnblogs.com 

Referer:用来说明请求是从哪个站点发起的。值包括协议、域名、查询参数,但不包括锚点(或称hash);所有类型的request中都会有此字段,如果是从浏览器直接输入地址发起request则值为空。示例: https://www.cnblogs.com/css/blog-common.min.css?v=KY 。由于Referer中会包含查询参数,故原始的URI中的查询参数若包含ID或密码等敏感信息则可能导致信息泄露,所以说别把敏感信息放URI中!但由于hash不被包括在内,所以确实需要的话可以将敏感信息放在URI的hash中,OAuth2.0的第二种授权模式就采用了这种方式返回token。

Origin:用来说明请求是从哪个站点发起的。值包括且仅包括协议和域名;这个参数一般只存在于CORS跨域请求中,可以看到response有对应的header:Access-Control-Allow-Origin。

 

 

参考资料

 

以上是关于HTTP协议的主要内容,如果未能解决你的问题,请参考以下文章

怎么用http协议实现安卓数据

CPNtools协议建模安全分析---实例变迁标记

HTTP客户端代码片段

高效Web开发的10个jQuery代码片段

如何从一个片段导航到另一个片段?

这两个代码片段有啥区别?