2023年7月3日发(作者:)
Wireshark抓包分析HTTP请求、响应报⽂格式⽂章⽬录HTTP 协议再规范⽂档⾥详细定义了报⽂的格式,规定了组成部分,解析规则,还有处理策略,所以可以在 TCP/IP 层之上实现丰富灵活的功能,例如连接控制、缓存管理、数据编码、内容协商报⽂结构HTTP 协议是⼀个”纯⽂本“的协议,在实际传输的数据前要附加⼀些头数据,不过头数据都是ASCII码的⽂本,可以很容易地⽤⾁眼阅读,不⽤借助程序解析也能够看懂HTTP协议的请求报⽂和响应报⽂的结构基本相同,由三⼤部分组成:起始⾏(start line)描述请求或响应的基本信息头部字段集合(header)使⽤ key-value 形式更详细说明报⽂消息正⽂(entity)实际传输的数据,不⼀定是纯⽂本,可以是图⽚、视频等⼆进制数据其中前两部分起始⾏和头部字段经常合称为”请求头“或”响应头“,消息正⽂⼜称为”实体“,但与”header“对应,很多时候就直接称为”body“HTTP协议规定报⽂必须有header,但可以没有body,⽽且在header之后必须要有⼀个“空⾏”,也就是“CRLF”,⼗六机制的“0D0A”所以,⼀个完整的HTTP报⽂就像下图的这样,注意在header和body之间有⼀个“空⾏”接下来看获取的 GET 请求报⽂信息在这个浏览器发出的请求报⽂⾥,第⼀⾏“GET / HTTP/1.1”就是请求⾏,⽽后⾯的“Host”“Connection”等等都属于header,报⽂的最后是⼀个空⽩⾏结束,没有body其实浏览器发送GET请求的时HTTP报⽂经常是只有header⽽没body。,虽然HTTP协议对header的⼤⼩没有做限制,但各个Web服务器都不允许过⼤的请求头,因为头部太⼤可能会占⽤⼤量的服务器资源,影响运⾏效率HTTP 请求报⽂的请求⾏请求报⽂⾥的起始⾏也就是请求⾏(request line),简要描述了客户端想要如何操作服务器端的资源请求⾏由三部分构成:请求⽅法:是⼀个动词,如GET/POST,表⽰对资源的操作请求⽬标:通常是⼀个URI,标记了请求⽅法要操作的资源版本号:表⽰报⽂使⽤的HTTP协议版本这三个部分通常使⽤空格(space)来分隔,最后要⽤CRLF换⾏表⽰结束还是⽤Wireshark抓包的数据来举例:GET / HTTP/1.1在这个请求⾏⾥,“GET”是请求⽅法,“/”是请求标,“HTTP/1.1”是版本号,把这三部分连起来,意思就是“服务器你好,我想获取⽹站根⽬录下的默认⽂件,我⽤的协议版本号是1.1请求⽅法蒂姆·伯纳斯-李最初设想的是要⽤HTTP协议构建⼀个超链接⽂档系统,使⽤URI来定位这些⽂档,也就是资源。那么,该怎么在协议⾥操作这些资源呢?所以,就出现了“请求⽅法”。实际含义就是客户端发出了⼀个“动作指令”,要求服务器端对URI定位的资源执⾏这个动作HTTP/1.1规定了⼋种⽅法,单词都必须是⼤写的形式:GET:获取资源,可理解为读取或下载数据HEAD:获取资源的元信息POST:向资源提交数据,相当于写⼊或上传数据PUT:类似 POSTDELETE:删除资源CONNECT:建⽴特殊的连接隧道OPTIONS:列出可对资源实⾏的⽅法TRACE:追踪请求-响应的传输路径有点像对⽂件或数据库的“增删改查”操作,只不过这些动作操作的⽬标不是本地资源,⽽是远程服务器上的资源,所以只能由客户端“请求”或者“指⽰”服务器来完成既然请求⽅法是⼀个“指⽰”,那么客户端⾃然就没有决定权,服务器掌控着所有资源,也就有绝对的决策权⼒。它收到HTTP请求报⽂后,看到⾥⾯的请求⽅法,可以执⾏也可以拒绝,或者改变动作的含义,毕竟HTTP是⼀个“协议”,两边都要“商量着来”⽐如,发起了⼀个GET请求,想获取“/orders”这个⽂件,但这个⽂件保密级别⽐较⾼,不是谁都能看的,服务器就可以有如下的⼏种响应⽅式:假装这个⽂件不存在,直接返回⼀个404 Not found报⽂稍微友好⼀点,明确告诉你有这个⽂件,但不允许访问,返回⼀个403 Forbidden再宽松⼀些,返回405 Method Not Allowed,然后⽤Allow头告诉你可以⽤HEAD⽅法获取⽂件的元信息举⼏个个⽐较常⽤的⽅法说明:GET/HEAD请求从服务器获取资源,这个资源既可以是静态的⽂本、页⾯、图⽚、视频,也可以是由PHP、Java动态⽣成的页⾯或者其他格式的数据GET⽅法虽然基本动作⽐较简单,但搭配URI和其他头字段就能实现对资源更精细操作,例如,在URI后使⽤“#”,可以在获取页⾯后直接定位到某个标签所在的位置;使⽤If-Modified-Since字段就变成了“有条件的请求”,仅当资源被修改时才会执⾏获取动作;使⽤Range字段就是“范围请求”,只获取资源的⼀部分数据HEAD⽅法与GET⽅法类似,也是请求从服务器获取资源,服务器的处理机制也是⼀样的,但服务器不会返回请求的实体数据,只传回响应头,就是资源的“元信息”。可以看做是GET⽅法的⼀个“简化版”或者“轻量版”。因为它的响应头与GET完全相同,所以可以⽤在很多并不真正需要资源的场合,避免传输body数据的浪费⽐如,想要检查⼀个⽂件是否存在,只要发个HEAD请求就可以了,没有必要⽤GET把整个⽂件都取下来。再⽐如,要检查⽂件是否有最新版本,同样也应该⽤HEAD,服务器会在响应头⾥把⽂件的修改时间传回来POST/PUTGET和HEAD⽅法是从服务器获取数据,⽽POST和PUT⽅法则是相反操作,向URI指定的资源提交数据,数据就放在报⽂的body⾥⽐如,上论坛灌⽔,敲了⼀堆字后点击“发帖”按钮,浏览器就执⾏了⼀次POST请求,把你的⽂字放进报⽂的body⾥,然后拼好POST请求头,通过TCP协议发给服务器。⼜⽐如,上购物⽹站,看到了⼀件⼼仪的商品,点击“加⼊购物车”,这时也会有POST请求,浏览器会把商品ID发给服务器,服务器再把ID写⼊你的购物车相关的数据库记录PUT的作⽤与POST类似,也可以向服务器提交数据,但与POST存在微妙的不同,通常POST表⽰的是“新建”“create”的含义,⽽PUT则是“修改”“update”的含义在实际应⽤中,PUT⽤到的⽐较少。⽽且,因为它与POST的语义、功能太过近似,有的服务器甚⾄就直接禁⽌使⽤PUT⽅法,只⽤POST⽅法上传数据其他⽅法DELETE⽅法指⽰服务器删除资源,因为这个动作危险性太⼤,所以通常服务器不会执⾏真正的删除操作,⽽是对资源做⼀个删除标记。当然,更多的时候服务器就直接不处理DELETE请求CONNECT是⼀个⽐较特殊的⽅法,要求服务器为客户端和另⼀台远程服务器建⽴⼀条特殊的连接隧道,这时Web服务器在中间充当了代理的⾓⾊OPTIONS⽅法要求服务器列出可对资源实⾏的操作⽅法,在响应头的Allow字段⾥返回。它的功能很有限,⽤处也不⼤,有的服务器(例如Nginx)⼲脆就没有实现对它的⽀持TRACE⽅法多⽤于对HTTP链路的测试或诊断,可以显⽰出请求-响应的传输路径。它的本意是好的,但存在漏洞,会泄漏⽹站的信息,所以Web服务器通常也是禁⽌使⽤URIURI,也就是统⼀资源标识符(Uniform Resource Identifier)包含有URL和URN两个部分,在HTTP世界⾥⽤的⽹址实际上是URL,即统⼀资源定位符(Uniform Resource Locator)。但因为URL实在是太普及了,所以常常把这两者简单地视为相等URI 的格式URI本质上是⼀个字符串,这个字符串的作⽤是唯⼀地标记资源的位置或者名字,它不仅能够标记万维⽹的资源,也可以标记其他的,如邮件系统、本地⽂件系统等任意资源。⽽“资源”既可以是存在磁盘上的静态⽂本、页⾯数据,也可以是由Java、PHP提供的动态服务下⾯的这张图显⽰了URI最常⽤的形式,由scheme、host:port、path和query四个部分组成,但有的部分可以视情况省略scheme:“协议名”,表⽰资源应该使⽤哪种协议访问,浏览器通过你的应⽤程序看到URI⾥的scheme,就知道下⼀步该怎么⾛了,会调⽤相应的HTTP或者HTTPS下层API。在scheme之后,必须是三个特定的字符 : / / ,把scheme和后⾯的部分分开host:port,即主机名加端⼝号,表⽰资源所在主机,主机名可以是IP地址或者域名的形式,必须要有,否则浏览器就会找不到服务器。但端⼝号有时可以省略,浏览器等客户端会依据scheme使⽤默认的端⼝号,例如HTTP的默认端⼝号是80,HTTPS的默认端⼝号是443Path,有了协议名和主机地址、端⼝号,再加上后⾯标记资源所在⽬录,浏览器就可以连接服务器访问资源。URI⾥path采⽤了类似⽂件系统“⽬录”“路径”的表⽰⽅式,因为早期互联⽹上的计算机多是UNIX系统,所以采⽤了UNIX的“/”风格。URI的path部分必须以“/”开始协议名 http主机名 端⼝号省略,对于 http 协议默认 80路径部分也被省略,默认就是⼀个“/”,表⽰根⽬录
:8080/11-1主机名
端⼝号 8080路径是 /11-1HTTP协议标准⽂档RFC7230的URI/html/rfc7230主机名 路径是 /html/rfc7230file:///D:/http_study/www/协议名 file,表⽰这是本地⽂件三个斜杠⾥的前两个属于URI特殊分隔符 ://主机名被省略,file类型URI的“特例”,它允许省略主机名,默认是本机localhost路径是 /D:/http_study/www/但对于HTTP或HTTPS这样的⽹络通信协议主机名是绝对不能省略的,会导致浏览器⽆法找到服务器查询参数:URI后⾯还有⼀个“query”部分,它在path之后,⽤⼀个“?”开始,但不包含“?”,表⽰对资源附加的额外要求。查询参数query有⼀套⾃⼰的格式,是多个“key=value”的字符串,这些KV值⽤字 符“&”连接,浏览器和客户端都可以按照这个格式把长串的查询参数解析成可理解的字典或关联数组形式例如:获取商品图⽚,但想要⼀个32×32的缩略图版本;获取商品列表,但要按某种规则做分页和排序;跳转页⾯,但想要标记跳转前的原始页⾯URI的完整格式第⼀个多出的部分是协议名之后、主机名之前的⾝份信息“user:passwd@”,表⽰登录主机时的⽤户名和密码,但现在已经不推荐使⽤这种形式了(RFC7230),因为它把敏感信息以明⽂形式暴露出来,存在严重的安全隐患第⼆个多出的部分是查询参数后的⽚段标识符“#fragment”,它是URI所定位的资源内部的⼀个“锚点”或者说是“标签”,浏览器可以在获取资源后直接跳转到它指⽰的位置。但⽚段标识符仅能由浏览器这样的客户端使⽤,服务器是看不到的。也就是说,浏览器永远不会把带“#fragment”的URI发送给服务器,服务器也永远不会⽤这种⽅式去处理资源的⽚段URI 的编码在URI⾥只能使⽤ASCII码。对于ASCII码以外的字符集和特殊字符做⼀个特殊的操作,把它们转换成与URI语义不冲突的形式。这在RFC规范⾥称为“escape”和“unescape”,俗称“转义”HTTP 响应报⽂的状态⾏看完了请求⾏,我们再看响应报⽂⾥的起始⾏,在这⾥它不叫“响应⾏”,⽽是叫“状态⾏”(status line),意思是服务器响应的状态⽐起请求⾏来说,状态⾏要简单⼀些,同样也是由三部分构成:版本号:表⽰报⽂使⽤的HTTP协议版本状态码:三个数字,表⽰处理的结果,⽐如200是成功,500是服务器错误原因:对状态码的⼀个解释说明看⼀下之前 Wireshark 抓包⾥的响应报⽂,状态⾏是:HTTP/1.1 200 OK意思就是:“浏览器你好,我已经处理完了你的请求,这个报⽂使⽤的协议版本号是1.1,状态码是200,⼀切OK。”另⼀个“GET / HTTP/1.1”的响应报⽂状态⾏是:HTTP/1.1 404 Not Found意思是:抱歉啊浏览器,刚才你的请求收到了,但我没找到你要的资源,错误代码是404状态码它是⼀个⼗进制数字,表⽰服务器对请求的处理结果。客户端可以依据代码适时转换处理状态,例如继续发送请求、切换协议,重定向跳转等,有那么点TCP状态转换的意思⽬前RFC标准⾥规定的状态码是三位数,所以取值范围就是从000到999。RFC标准把状态码分成了五类,⽤数字的第⼀位表⽰分类,⽽0-99不⽤,由000-999变成了100~599这五类具体含义:1××:提⽰信息,表⽰⽬前是协议处理的中间状态,还需要后续的操作2××:成功,报⽂已经收到并被正确处理3××:重定向,资源位置发⽣变动,需要客户端重新发送请求4××:客户端错误,请求报⽂有误,服务器⽆法处理5××:服务器错误,服务器在处理请求时内部发⽣了错误接下来逐个解释:1××类状态码属于提⽰信息,是协议处理的中间状态,实际能够⽤到的时候少。“101 Switching Protocols”。它的意思是客户端使⽤Upgrade头字段,要求在HTTP协议的基础上改成其他的协议继续通信,⽐如WebSocket。⽽如果服务器也同意变更协议,就会发送状态码101,但这之后的数据传输就不会再使⽤HTTP了2××类状态码表⽰服务器收到并成功处理了客户端的请求,这也是客户端最愿意看到的状态码200 OK 是最常见的成功状态码,表⽰⼀切正常,服务器如客户端所期望的那样返回了处理结果,如果是⾮HEAD请求,通常在响应头后都会有body数据204 No Content 是另⼀个很常见的成功状态码,它的含义与“200 OK”基本相同,但响应头后没有body数据。所以对于Web服务器来说206 Partial Content 是HTTP分块下载或断点续传的基础,在客户端发送“范围请求”、要求获取资源的部分数据时出现,它与200⼀样,也是服务器成功处理了请求,但body⾥的数据不是资源的全部,⽽是其中的⼀部分。他还会伴随着头字段“Content-Range”,表⽰响应报⽂⾥body数据的具体范围,供客户端确认,例如“Content-Range: bytes 0-99/2000”,意思是此次获取的是总计2000个字节的前100个字节3××类状态码表⽰客户端请求的资源发⽣了变动,客户端必须⽤新的URI重新发送请求获取资源,也就是通常所说的“重定向”301 Moved Permanently俗称“永久重定向,含义是此次请求的资源已经不存在了,需要改⽤改⽤新的URI再次访问302 Found “临时重定向,意思是请求的资源还在,但需要暂时⽤另⼀个URI来访问⽐如,你的⽹站升级到了HTTPS,原来的HTTP不打算⽤了,这就是“永久”的,所以要配置301跳转,把所有的HTTP流量都切换到HTTPS再⽐如,今天夜⾥⽹站后台要系统维护,服务暂时不可⽤,这就属于“临时”的,可以配置成302跳转,把流量临时切换到⼀个静态通知页⾯,浏览器看到这个302就知道这只是暂时的情况,不会做缓存优化,第⼆天还会访问原来的地址304 Not Modified 表⽰资源未修改,⽤于缓存控制。它不具有通常的跳转含义,但可以理解成“重定向已到缓存的⽂件”(即“缓存重定向)4××类状态码表⽰客户端发送的请求报⽂有误,服务器⽆法处理400 Bad Request 是⼀个通⽤的错误码,表⽰请求报⽂有错误,但具体是数据格式错误、缺少请求头还是URI超长它没有明确说,只是⼀个笼统的错误,客户端看到400只会是“⼀头雾⽔”“不知所措”。所以,在开发Web应⽤时应当尽量避免给客户端返回400,⽽是要⽤其他更有明确含义的状态码。403 Forbidden 实际上不是客户端的请求出错,⽽是表⽰服务器禁⽌访问资源。原因可能多种多样,例如信息敏感、法律禁⽌等,如果服务器友好⼀点,可以在body⾥详细说明拒绝请求的原因,不过现实中通常都是直接给⼀个“闭门羹”。404 Not Found 可能是我们最常看见也是最不愿意看到的⼀个状态码,它的原意是资源在本服务器上未找到,所以⽆法提供给客户端。但现在已经被“⽤滥了”,只要服务器“不⾼兴”就可以给出个404,⽽我们也⽆从得知后⾯到底是真的未找到,还是有什么别的原因,某种程度上它⽐403还要令⼈讨厌。5××类状态码表⽰客户端请求报⽂正确,但服务器在处理时内部发⽣了错误,⽆法返回应有的响应数据,是服务器端的“错误码”500 Internal Server Error 与400类似,也是⼀个通⽤的错误码,服务器究竟发⽣了什么错误我们是不知道的。不过对于服务器来说这应该算是好事,通常不应该把服务器内部的详细信息,例如出错的函数调⽤栈告诉外界。虽然不利于调试,但能够防⽌⿊客的窥探或者分析501 Not Implemented 表⽰客户端请求的功能还不⽀持,这个错误码⽐500要“温和”⼀些,和“即将开业,敬请期待”的意思差不多,不过具体什么时候“开业”就不好说502 Bad Gateway 通常是服务器作为⽹关或者代理时返回的错误码,表⽰服务器⾃⾝⼯作正常,访问后端服务器时发⽣了错误,但具体的错误原因也是不知道的503 Service Unavailable 表⽰服务器当前很忙,暂时⽆法响应服务,我们上⽹时有时候遇到的“⽹络服务正忙,请稍后重试”的提⽰信息就是状态码503。是⼀个“临时”的状态,很可能过⼏秒钟后服务器就不那么忙了,可以继续提供服务,所以503响应报⽂⾥通常还会有⼀个“Retry-After”字段,指⽰客户端可以在多久以后再次尝试发送请求HTTP 请求、响应头部字段请求头和响应头的结构是基本⼀样的,唯⼀的区别是起始⾏请求⾏或状态⾏再加上头部字段集合就构成了HTTP报⽂⾥完整的请求头或响应头,对⽐两个⽰意图:头部字段是key-value的形式,key和value之间⽤ :分隔,最后⽤CRLF换⾏表⽰字段结束。⽐如在“Host:127.0.0.1”这⼀⾏⾥key就是“Host”,value就是“127.0.0.1”HTTP头字段⾮常灵活,不仅可以使⽤标准⾥的Host、Connection等已有头,也可以任意添加⾃定义头,这就给HTTP协议带来了⽆限的扩展可能。不过使⽤头字段需要注意下⾯⼏点:字段名不区分⼤⼩写,例如 Host 也可以写成 host ,但⾸字母⼤写的可读性更好字段名⾥不允许出现空格,可以使⽤连字符 - ,但不能使⽤下划线 _ 。例如,test-name是合法的字段名,⽽ test name 和test_name是不正确的字段名后⾯必须紧接着:不能有空格,⽽:后的字段值前可以有多个空格字段的顺序是没有意义的,可以任意排列不影响语义字段原则上不能重复,除⾮这个字段本⾝的语义允许,例如Set-Cookie常⽤头字段HTTP协议规定了⾮常多的头部字段,实现各种各样的功能,但基本上可以分为四⼤类:通⽤字段:在请求头和响应头⾥都可以出现请求字段:仅能出现在请求头⾥,进⼀步说明请求信息或者额外的附加条件响应字段:仅能出现在响应头⾥,补充说明响应报⽂的信息实体字段:它实际上属于通⽤字段,但专门描述body的额外信息⼏个最基本的头字段:Date 通⽤字段,通常出现在响应头⾥,表⽰HTTP报⽂创建的时间,客户端可以使⽤这个时间再搭配其他字段决定缓存策略Cache-Control ⽤于指定缓存指令,缓存指令是单向的(响应中出现的缓存指令在请求中未必会出现),且是独⽴的(⼀个消息的缓存指令不会影响另⼀个消息处理的缓存机制)Host 请求字段 告诉服务器这个请求应该由哪个主机来处理,当⼀台计算机上托管了多个虚拟主机的时候,服务器端就需要⽤Host字段来选择,有点像是⼀个简单的“路由重定向”例如在127.0.0.1上有三个虚拟机:、 和 那么当使⽤域名的⽅式访问时,就必须要⽤Host字段来区分这三个IP相同但域名不同的⽹站,否则服务器就会找不到合适的虚拟主机,⽆法处理User-Agent 请求字段,发送请求的浏览器类型、操作系统等信息Accept 请求字段,客户端可识别内容类型列表,⽤于指定客户端接收哪些类型信息Server 响应字段,只能出现在响应头⾥。它告诉客户端当前正在提供Web服务的软件名称和版本号,例如“Server:openresty/1.15.8.1”,即使⽤的是OpenResty 1.15.8.1Server字段也不是必须要出现的,因为这会把服务器的⼀部分信息暴露给外界,如果这个版本恰好存在 bug,那么⿊客就有可能利⽤bug攻陷服务器。所以,有的⽹站响应头⾥要么没有这个字段,要么就给出⼀个完全⽆关的描述信息⽐如GitHub,它的Server字段⾥就看不出是使⽤了Apache还是Nginx,只是显⽰为“”实体字段 Content-Length,它表⽰报⽂⾥body的长度,也就是请求头或响应头空⾏后⾯数据的长度。服务器看到这个字段,就知道了后续有多少数据,可以直接接收。如果没有这个字段,那么body就是不定长的,需要使⽤chunked⽅式分段传输实体字段 Content-Type发送给接收者实体正⽂媒体类型Expires ,实体报头给出响应过期的⽇期和时间
发布者:admin,转转请注明出处:http://www.yc00.com/web/1688340589a123245.html
评论列表(0条)