menu ChaYedan
HTTP详解
451 浏览 | 2020-05-08 | 阅读时间: 约 8 分钟 | 分类: 通用 | 标签: HTTP
请注意,本文编写于 874 天前,最后修改于 874 天前,其中某些信息可能已经过时。

HTTP详解

简介

HTTP 协议的全称是(HyperText Transfer Protocol),翻译过来就是超文本传输协议

超文本是超级文本的缩写,是指超越文本限制或者超链接,比如:图片、音乐、视频、超链接等等都属于超文本。

HTTP 协议的制作者是蒂姆·伯纳斯-李,1991年设计出来的,HTTP 协议设计之前目的是传输网页数据的,现在允许传输任意类型的数据

传输 HTTP 协议格式的数据是基于 TCP 传输协议的,发送数据之前需要先建立连接。

HTTP协议规定了浏览器和 Web 服务器通信数据的格式,也就是说浏览器和web服务器通信需要使用http协议

下图是详细的常用协议在模型哪一层的分布

图源自https://www.jianshu.com/p/6e9e4156ece3

HTTP 工作原理

HTTP协议工作于客户端-服务端架构上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。

Web服务器有:Apache服务器,IIS服务器(Internet Information Services)等。

Web服务器根据接收到的请求后,向客户端发送响应信息。

HTTP默认端口号为80,但是你也可以改为8080或者其他端口。

HTTP三点注意事项:

  • HTTP是无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
  • HTTP是媒体独立的:这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。客户端以及服务器指定使用适合的MIME-type内容类型。
  • HTTP是无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

HTTP 请求报文

下面以典型的GET和POST的请求方式来详细说明

GET

GET / HTTP/2
Host: chayedan.site # 服务器的主机地址和端口号,默认是80
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0 # 用户代理,也就是客户端的名称
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 # 可接受的数据类型
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 #可接受的语言
Accept-Encoding: gzip, deflate, br # 可接受的压缩格式
Connection: keep-alive # 和服务端保持长连接
Cookie: Hm_lvt_ac61e8c5c9bb5640fa5813ec00bcdfe7=1587977550,1588581976,1588592256,1588648850; 76fcc681dc6f594f97b404a129f1f9b4__typecho_remember_author=keke; 76fcc681dc6f594f97b404a129f1f9b4__typecho_remember_mail=725%40126.com; 76fcc681dc6f594f97b404a129f1f9b4__typecho_remember_url=http%3A%2F%2Fbilibili.com; brightness=
Upgrade-Insecure-Requests: 1 # 让浏览器升级不安全请求,使用https请求

这是访问我博客首页的请求报文原始数据。

其中第一行是请求行,标明请求方式,请求的资源路径和HTTP协议版本(多嘴一句,现在HTTP已经到2辣)

第二行开始是请求头,包含各种请求的信息,详情请看注释

另外需要着重强调的是换行符的问题,在HTTP中的换行符,统一使用的是\r\n

虽然我们常说GET方式是不能有请求体的,但是其实在HTTP协议中,并没有这样规定,GET方式也是可以带请求体的,但是人们约定俗成,因为GET方式主要是获取信息即使需要传送的参数,也是写在URL后面传送过去

POST

因为我博客不好演示POST方式,所以这里以谷歌翻译为例

POST /log?format=json&hasfast=true&authuser=0 HTTP/1.1
Host: play.google.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
X-Goog-AuthUser: 0
Content-Type: application/x-www-form-urlencoded;charset=utf-8
Content-Length: 770
Origin: https://translate.google.cn
Connection: keep-alive
Referer: https://translate.google.cn/
Cookie: 1P_JAR=2020-05-07-03; NID=204=BZl96p70L3lsEktsjJQbq5TA6pDDN5SeTQP5QsLxeL3L3bWOti1-sOy0ETUR3aseW1iLc5xjfSTITXW04wqKr41K3bd1nFnGJ1DbipvMGF4e56mn3mVrIjWhz0-z_fQ9RocUdM0NovW4llR1ODIK7ymFAa_C_R68aArwVH1ND5I
TE: Trailers

[[1,null,null,null,null,null,null,null,null,null,[null,null,null,null,"zh-CN"]],375,[["1588842293310",null,[],null,null,null,null,"[\"zh-CN\",null,null,null,null,null,null,null,null,null,null,null,null,\"\",null,\"auto\",null,null,null,null,null,null,null,null,null,[],null,null,null,null,1,0,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,\"zh-CN\",null,\"hello world\",0,null,null,null,null,null,null,null,null,null,null,null,2,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[]]",null,null,null,null,null,null,null,[null,[],null,"[[],[],[17259,15700190,15700271,15700346,15700362,15700370],[]]"],null,null,null,[],6,null,null,null,null,null,[]]],"1588842294038",[],null,null,null,null,null,null,null,null,0]

虽然我不知道这谷歌翻译为什么发了POST请求给play.google还发了一堆乱七八糟的东西(((

但是需要明白的是,POST比GET多了一个东西,那就是最后这个乱七八糟的东西,请求体

特别需要注意的是:请求头和请求体之间隔了一个空行,这是HTTP的规范。

HTTP响应报文

这是我博客的响应报文

HTTP/2 200 OK
server: nginx # 服务器名称
date: Thu, 07 May 2020 09:14:32 GMT # 服务端的响应时间
content-type: text/html; charset=UTF-8 # 内容类型
vary: Accept-Encoding # 处理网站的压缩版本,不算典型的响应头信息
x-pingback: https://chayedan.site/index.php/action/xmlrpc
content-encoding: gzip # 压缩形式
X-Firefox-Spdy: h2

<!DOCTYPE html><html lang=“en”> …</html> # 响应给客户端的数据

第一行是响应行或者说状态行,标明HTTP协议版本和状态码以及状态描述

第二行开始是响应头,一直到空行为止

第十行是响应体,也就是在游览器中渲染的html代码等

需要注意的是,响应头和响应体中间也是有空行的,且空行使用的是\r\n

附录

常见的HTTP状态码

状态码说明
200请求成功
307重定向
400错误的请求,请求地址或者参数有误
404请求资源在服务器不存在
500服务器内部源代码出现错误

请求方法(1.1版本)

方法描述
GET请求指定的页面信息,并返回实体主体。
HEAD类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头
POST向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。
PUT从客户端向服务器传送的数据取代指定的文档的内容。
DELETE请求服务器删除指定的页面。
CONNECTHTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
OPTIONS允许客户端查看服务器的性能。
TRACE回显服务器收到的请求,主要用于测试或诊断。
PATCH是对 PUT 方法的补充,用来对已知资源进行局部更新 。

请求体信息

字段名说明示例
Accept能够接受的回应内容类型(Content-Types)。参见内容协商。Accept: text/plain常设
Accept-Charset能够接受的字符集Accept-Charset: utf-8常设
Accept-Encoding能够接受的编码方式列表。参考HTTP压缩。Accept-Encoding: gzip, deflate常设
Accept-Language能够接受的回应内容的自然语言列表。参考 内容协商 。Accept-Language: en-US常设
Accept-Datetime能够接受的按照时间来表示的版本Accept-Datetime: Thu, 31 May 2007 20:35:00 GMT临时
Authorization用于超文本传输协议的认证的认证信息Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==常设
Cache-Control用来指定在这次的请求/响应链中的所有缓存机制 都必须 遵守的指令Cache-Control: no-cache常设
Connection该浏览器想要优先使用的连接类型[8]Connection: keep-alive`Connection: Upgrade`常设
Cookie之前由服务器通过 Set- Cookie (下文详述)发送的一个 超文本传输协议CookieCookie: $Version=1; Skin=new;常设: 标准
Content-Length以 八位字节数组 (8位的字节)表示的请求体的长度Content-Length: 348常设
Content-MD5请求体的内容的二进制 MD5 散列值,以 Base64 编码的结果Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==过时的
Content-Type请求体的 多媒体类型 (用于POST和PUT请求中)Content-Type: application/x-www-form-urlencoded常设
Date发送该消息的日期和时间(按照 RFC 7231 中定义的"超文本传输协议日期"格式来发送)Date: Tue, 15 Nov 1994 08:12:31 GMT常设
Expect表明客户端要求服务器做出特定的行为Expect: 100-continue常设
From发起此请求的用户的邮件地址From: user@example.com常设
Host服务器的域名(用于虚拟主机 ),以及服务器所监听的传输控制协议端口号。如果所请求的端口是对应的服务的标准端口,则端口号可被省略。 自超文件传输协议版本1.1(HTTP/1.1)开始便是必需字段。Host: en.wikipedia.org:80`Host: en.wikipedia.org`常设
If-Match仅当客户端提供的实体与服务器上对应的实体相匹配时,才进行对应的操作。主要作用时,用作像 PUT 这样的方法中,仅当从用户上次更新某个资源以来,该资源未被修改的情况下,才更新该资源。If-Match: "737060cd8c284d8af7ad3082f209582d"常设
If-Modified-Since允许在对应的内容未被修改的情况下返回304未修改( 304 Not Modified )If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT常设
If-None-Match允许在对应的内容未被修改的情况下返回304未修改( 304 Not Modified ),参考 超文本传输协议 的实体标记If-None-Match: "737060cd8c284d8af7ad3082f209582d"常设
If-Range如果该实体未被修改过,则向我发送我所缺少的那一个或多个部分;否则,发送整个新的实体If-Range: "737060cd8c284d8af7ad3082f209582d"常设
If-Unmodified-Since仅当该实体自某个特定时间已来未被修改的情况下,才发送回应。If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT常设
Max-Forwards限制该消息可被代理及网关转发的次数。Max-Forwards: 10常设
Origin发起一个针对 跨来源资源共享 的请求(要求服务器在回应中加入一个‘访问控制-允许来源’('Access-Control-Allow-Origin')字段)。Origin: http://www.example-social-network.com常设: 标准
Pragma与具体的实现相关,这些字段可能在请求/回应链中的任何时候产生多种效果。Pragma: no-cache常设但不常用
Proxy-Authorization用来向代理进行认证的认证信息。Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==常设
Range仅请求某个实体的一部分。字节偏移以0开始。参见字节服务。Range: bytes=500-999常设
Referer表示浏览器所访问的前一个页面,正是那个页面上的某个链接将浏览器带到了当前所请求的这个页面。Referer: http://en.wikipedia.org/wiki/Main_Page常设
TE浏览器预期接受的传输编码方式:可使用回应协议头 Transfer-Encoding 字段中的值;另外还可用"trailers"(与"分块 "传输方式相关)这个值来表明浏览器希望在最后一个尺寸为0的块之后还接收到一些额外的字段。TE: trailers, deflate常设
User-Agent浏览器的浏览器身份标识字符串User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0常设
Upgrade要求服务器升级到另一个协议。Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11常设
Via向服务器告知,这个请求是由哪些代理发出的。Via: 1.0 fred, 1.1 example.com (Apache/1.1)常设
Warning一个一般性的警告,告知,在实体内容体中可能存在错误。Warning: 199 Miscellaneous warning常设

响应头信息

应答头说明
Allow服务器支持哪些请求方法(如GET、POST等)。
Content-Encoding文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。Java的GZIPOutputStream可以很方便地进行gzip压缩,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet应该通过查看Accept-Encoding头(即request.getHeader("Accept-Encoding"))检查浏览器是否支持gzip,为支持gzip的浏览器返回经gzip压缩的HTML页面,为其他浏览器返回普通页面。
Content-Length表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。如果你想要利用持久连接的优势,可以把输出文档写入 ByteArrayOutputStream,完成后查看其大小,然后把该值放入Content-Length头,最后通过byteArrayStream.writeTo(response.getOutputStream()发送内容。
Content-Type表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置Content-Type,因此HttpServletResponse提供了一个专用的方法setContentType。
Date当前的GMT时间。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。
Expires应该在什么时候认为文档已经过期,从而不再缓存它?
Last-Modified文档的最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置。
Location表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。
Refresh表示浏览器应该在多少时间之后刷新文档,以秒计。除了刷新当前文档之外,你还可以通过setHeader("Refresh", "5; URL=http://host/path")让浏览器读取指定的页面。 注意这种功能通常是通过设置HTML页面HEAD区的<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path">实现,这是因为,自动刷新或重定向对于那些不能使用CGI或Servlet的HTML编写者十分重要。但是,对于Servlet来说,直接设置Refresh头更加方便。 注意Refresh的意义是"N秒之后刷新本页面或访问指定页面",而不是"每隔N秒刷新本页面或访问指定页面"。因此,连续刷新要求每次都发送一个Refresh头,而发送204状态代码则可以阻止浏览器继续刷新,不管是使用Refresh头还是<META HTTP-EQUIV="Refresh" ...>。 注意Refresh头不属于HTTP 1.1正式规范的一部分,而是一个扩展,但Netscape和IE都支持它。
Server服务器名字。Servlet一般不设置这个值,而是由Web服务器自己设置。
Set-Cookie设置和页面关联的Cookie。Servlet不应使用response.setHeader("Set-Cookie", ...),而是应使用HttpServletResponse提供的专用方法addCookie。参见下文有关Cookie设置的讨论。
WWW-Authenticate客户应该在Authorization头中提供什么类型的授权信息?在包含401(Unauthorized)状态行的应答中这个头是必需的。例如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"")。 注意Servlet一般不进行这方面的处理,而是让Web服务器的专门机制来控制受密码保护页面的访问(例如.htaccess)。

参考资料

https://zh.wikipedia.org/wiki/HTTP%E5%A4%B4%E5%AD%97%E6%AE%B5

https://www.runoob.com/http/http-tutorial.html

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

发表评论

email
web

全部评论 (暂无评论)

info 还没有任何评论,快来留言吧!