计算机网络协议之http协议(四)

一、HTTP协议概述
  HTTP协议又称超文本传输协议,是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。HTTP协议的特点如下:
  1. 基于客户/服务器模式。
  2. 在HTTP / 0.9和1.0中每次连接只处理一个请求。
  3. 服务器不保留与客户交易时的任何状态,即无状态模式。
  4. 在HTTP / 1.1中,引入了保持活动机制,其中连接可以重用于多个请求。

  请求响应模型的过程如下:

  1. 客户与服务器建立连接:基于TCP的三次握手。
  2. 客户向服务器提出请求:发送请求数据。
  3. 服务器接受请求:接收请求数据,并根据请求返回相应的数据作为应答。
  4. 客户与服务器关闭连接。

二、HTTP报文

  HTTP协议以报文的方式传输数据,请求报文由请求行、请求头、空行、请求体组成,响应报文由响应行、响应头、空行、响应体组成,格式如下:

 

  以下是一个真实请求http://192.168.1.193:9000/的请求报文和响应报文:

<!-- 请求报文 -->
GET / HTTP/1.1       <!-- 请求行 -->
Host: 192.168.1.193:9000   <!-- 请求头,会携带的key-value类型的多组参数 -->
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
                            <!-- 空行, 用于分割请求头和请求体-->
  <!-- 请求体数据,此案例没用请求体数据 -->
<!-- 响应报文 -->
HTTP/1.1 200 OK    <!-- 响应行-->
Accept-Ranges: bytes     <!-- 响应头,包含key-value格式的参数信息-->
Cache-Control: no-cache, no-store, must-revalidate
Content-Length: 23203
Content-Type: text/html; charset=utf-8
Last-Modified: Thu, 18 Mar 2021 19:53:17 GMT
X-Content-Type-Options: nosniff
X-Xss-Protection: 1; mode=block
Date: Fri, 09 Jun 2023 06:52:21 GMT
                                <!-- 空行,用于分割请求头和响应体-->
<!-- 以下是响应报文主体-->
<!DOCTYPE html
><html lang="en" ng-app="portainer">
  <head>
    <meta charset="utf-8" />
    <title>Portainer</title>
    <meta name="description" content="" />
    <meta name="author" content="Portainer.io" />

    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
    <!--[if lt IE 9]>
      <script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->

    <!-- Fav and touch icons -->
    <link rel="apple-touch-icon" sizes="180x180" href="dc4d092847be46242d8c013d1bc7c494.png" />
    <link rel="icon" type="image/png" sizes="32x32" href="5ba13dcb526292ae707310a54e103cd1.png" />
    <link rel="icon" type="image/png" sizes="16x16" href="f9508a64a1beb81be174e194573f7450.png" />
    <link rel="mask-icon" href="07745d55b001c85826eedd479285cdbb.svg" color="#5bbad5" />
    <meta name="msapplication-config" content="4806ce9049e1e082dd3da4063ceb0eea.xml" />
    <meta name="theme-color" content="#ffffff" />
  <link href="vendor.1.css" rel="stylesheet"><link href="main.50213a000e42f5c05bcc.css" rel="stylesheet"></head>

  <body ng-controller="MainController">
    <div
      id="page-wrapper"
      ng-class="{
        open: toggle && ['portainer.auth', 'portainer.updatePassword', 'portainer.init.admin', 'portainer.init.endpoint'].indexOf($state.current.name) === -1,
        nopadding: ['portainer.auth', 'portainer.updatePassword', 'portainer.init.admin', 'portainer.init.endpoint'].indexOf($state.current.name) > -1 || applicationState.loading
      }"
      ng-cloak
    >
      <div id="sideview" ui-view="sidebar" ng-if="!applicationState.loading"></div>

      <div id="content-wrapper">
        <div class="page-content">
          <div class="page-wrapper" ng-if="applicationState.loading">
            <!-- loading box -->
            <div class="container simple-box">
              <div class="col-md-6 col-md-offset-3 col-sm-6 col-sm-offset-3">
                <!-- loading box logo -->
                <div class="row">
                  <img ng-if="logo" ng-src="{{ logo }}" class="simple-box-logo" />
                  <img ng-if="!logo" src="5da83cfb4883a59354abeff852cb7394.png" class="simple-box-logo" alt="Portainer" />
                </div>
                <!-- !loading box logo -->
                <!-- panel -->
                <div class="row" style="text-align: center;">
                  Loading Portainer...
                  <i class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
                </div>
                <!-- !panel -->
              </div>
            </div>
            <!-- !loading box -->
          </div>

          <!-- Main Content -->
          <div id="view" ui-view="content" ng-if="!applicationState.loading"></div> </div
        ><!-- End Page Content --> </div
      ><!-- End Content Wrapper --> </div
    ><!-- End Page Wrapper -->
</body></html>

三、HTTP请求方法

  HTTP规范定义了8种请求方法,每种请求方法规定了客户和服务器之间不同的信息交换方式,常用的请求方法是GET和POST。服务器将根据客户请求完成相应操作,并以应答块形式返回给客户,最后关闭连接。

  1. GET请求:向指定的资源发出“显示”请求。使用GET方法应该只用在读取数据,而不该在该请求中包含更新、新增、删除等操作。
  2. HEAD请求:与GET方法一样,都是向服务器发出指定资源的请求,用于获取头信息。但是服务器只返回该该资源相关得元数据信息,而不返回正文主体。
  3. POST请求:向指定资源提交数据,数据被包含在请求体中,请求服务器进行处理。
  4. PUT请求:向指定URL传送更新资源。
  5. DELETE请求:请求服务器删除Request-URI所标识的资源。
  6. TRACE请求:回显服务器收到的请求,主要用于测试或诊断。
  7. OPTIONS请求:向服务器索取资源所支持的所有HTTP请求方法。
  8. CONNECT请求:CONNECT 方法可以开启一个客户端与所请求资源之间的双向沟通的通道,它可以用来创建隧道,实现点到点得连接。

四、HTTP响应状态码

  前面提到HTTP在响应报文中包含了响应状态码,用于告知客户端响应结果,HTTP状态码如下:

  1. 1xx(信息状态码):请求已被服务器接收,需要继续处理。
  2. 2xx(成功状态码):请求已成功被服务器接收、理解、并接受。
  3. 3xx(重定向状态码):需要后续操作才能完成这一请求。
  4. 4xx(客户端错误状态码):请求含有词法错误或者无法被执行。
  5. 5xx(服务器错误状态码):服务器在处理某个正确请求时发生错误。
100Continue 一个临时响应,是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。服务器必须在请求完成后向客户端发送一个最终响应。
101Switching Protocols 服务器已经理解了客户端的请求,并将通过Upgrade 消息头通知客户端采用不同的协议来完成这个请求。在发送完这个响应最后的空行后,服务器将会切换到在Upgrade 消息头中定义的那些协议。
102Processing 服务器已经收到了客户端的请求,正在处理,但暂时还没有可接触的响应。可以用于防止客户端超时并假设请求丢失。
200OK 请求已成功,请求所希望的响应头或数据体将随此响应返回。出现此状态码是表示正常状态。
201Created 请求已经被实现,而且有一个新的资源已经依据请求的需要而建立,且其 URI 已经随Location 头信息返回。假如需要的资源无法及时建立的话,应当返回 '202 Accepted'。
202 Accepted 服务器已接受请求,但尚未处理,最终该请求可能会也可能不会被执行。适合在异步操作的场合下返回一些当前处理状态的信息。
203Non-Authoritative Information 服务器已成功处理了请求,但返回的实体头部元信息不是在原始服务器上有效的确定集合,而是来自本地或者第三方的拷贝。
204No Content 服务器成功处理了请求,但不需要返回任何实体内容,并且希望返回更新了的元信息。响应可能通过实体头部的形式,返回新的或更新后的元信息。如果存在这些头部信息,则应当与所请求的变量相呼应。
205Reset Content 服务器成功处理了请求,且没有返回任何内容。但是与204响应不同,返回此状态码的响应要求请求者重置文档表单。
206Partial Content 服务器已经成功处理了部分 GET 请求。类似于 FlashGet 或者迅雷这类的 HTTP下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。
207Multi-Status 代表之后的消息体将是一个XML消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码。
300Multiple Choices 被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。用户或浏览器能够自行选择一个首选的地址进行重定向。
301Moved Permanently 被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。除非额外指定,否则这个响应是可缓存的。
302Move Temporarily 请求的资源临时从不同的 URI响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。
303See Other 当前请求的响应可以在另一个 URL 上被找到,而且客户端应当采用 GET 的方式访问那个资源。这个方法的存在主要是为了允许由脚本激活的POST请求输出重定向到一个新的资源。
304Not Modified 如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。304响应禁止包含消息体,因此始终以消息头后的第一个空行结尾。
305Use Proxy 被请求的资源必须通过指定的代理才能被访问。Location 域中将给出指定的代理所在的 URI 信息,接收者需要重复发送一个单独的请求,通过这个代理才能访问相应资源。只有原始服务器才能建立305响应。
306Switch Proxy
在最新版的规范中,306状态码已经不再被使用。
307Temporary Redirect 请求的资源临时从不同的URI 响应请求。新的临时性的URI 应当在响应的 Location 域中返回。除非这是一个HEAD 请求,否则响应的实体中应当包含指向新的URI 的超链接及简短说明。因为部分浏览器不能识别307响应,因此需要添加上述必要信息以便用户能够理解并向新的 URI 发出访问请求。
400Bad Request 语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。
401Unauthorized 当前请求需要用户验证。该响应必须包含一个适用于被请求资源的 WWW-Authenticate 信息头用以询问用户信息。客户端可以重复提交一个包含恰当的 Authorization 头信息的请求。如果当前请求已经包含了 Authorization 证书,那么401响应代表着服务器验证已经拒绝了那些证书。如果401响应包含了与前一个响应相同的身份验证询问,且浏览器已经至少尝试了一次验证,那么浏览器应当向用户展示响应中包含的实体信息,因为这个实体信息中可能包含了相关诊断信息。
402Payment Required 该状态码是为了将来可能的需求而预留的。
403Forbidden 服务器已经理解请求,但是拒绝执行它。与401响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。如果这不是一个 HEAD 请求,而且服务器希望能够讲清楚为何请求不能被执行,那么就应该在实体内描述拒绝的原因。当然服务器也可以返回一个404响应,假如它不希望让客户端获得任何信息。
404Not Found 请求失败,请求所希望得到的资源未被在服务器上发现。
405Method Not Allowed 请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow 头信息用以表示出当前资源能够接受的请求方法的列表。
406Not Acceptable 请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体。
407Proxy Authentication Required 与401响应类似,只不过客户端必须在代理服务器上进行身份验证。代理服务器必须返回一个 Proxy-Authenticate 用以进行身份询问。客户端可以返回一个 Proxy-Authorization 信息头用以验证。
408Request Timeout 请求超时。客户端没有在服务器预备等待的时间内完成一个请求的发送。客户端可以随时再次提交这一请求而无需进行任何更改。
409Conflict 由于和被请求的资源的当前状态之间存在冲突,请求无法完成。这个代码只允许用在这样的情况下才能被使用:用户被认为能够解决冲突,并且会重新提交新的请求。该响应应当包含足够的信息以便用户发现冲突的源头。
410Gone 被请求的资源在服务器上已经不再可用,而且没有任何已知的转发地址。
411Length Required 服务器拒绝在没有定义 Content-Length 头的情况下接受请求。
412Precondition Failed 服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。这个状态码允许客户端在获取资源时在请求的元信息(请求头字段数据)中设置先决条件,以此避免该请求方法被应用到其希望的内容以外的资源上。
413Request Entity Too Large 服务器拒绝处理当前请求,因为该请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。此种情况下,服务器可以关闭连接以免客户端继续发送此请求。
414Request-URI Too Long 请求的URI 长度超过了服务器能够解释的长度,因此服务器拒绝对该请求提供服务。
415Unsupported Media Type 对于当前请求的方法和所请求的资源,请求中提交的实体并不是服务器中所支持的格式,因此请求被拒绝。
416Requested Range Not Satisfiable 如果请求中包含了 Range 请求头,并且 Range 中指定的任何数据范围都与当前资源的可用范围不重合,同时请求中又没有定义 If-Range 请求头,那么服务器就应当返回416状态码。
417Expectation Failed 在请求头 Expect 中指定的预期内容无法被服务器满足,或者这个服务器是一个代理服务器,它有明显的证据证明在当前路由的下一个节点上,Expect 的内容无法被满足。
421Misdirected Request 请求被指向到无法生成响应的服务器。
422Unprocessable Entity 请求格式正确,但是由于含有语义错误,无法响应。
423Locked 当前资源被锁定。
424Failed Dependency 由于之前的某个请求发生的错误,导致当前请求失败,例如 PROPPATCH。
425Too Early 代表服务器不愿意冒风险来处理该请求,原因是处理该请求可能会被“重放”,从而造成潜在的重放攻击。
426Upgrade Required 客户端应当切换到TLS/1.0。
449Retry With 由微软扩展,代表请求应当在执行完适当的操作后进行重试。
451 Unavailable For Legal Reasons 该请求因法律原因不可用。
500Internal Server Error 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器端的源代码出现错误时出现。
501Not Implemented 服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。
502Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
503Service Unavailable 由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个 Retry-After 头用以标明这个延迟时间。如果没有给出这个 Retry-After 信息,那么客户端应当以处理500响应的方式处理它。
504Gateway Timeout 作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器或者辅助服务器(例如DNS)收到响应。
505HTTP Version Not Supported 服务器不支持,或者拒绝支持在请求中使用的 HTTP 版本。这暗示着服务器不能或不愿使用与客户端相同的版本。响应中应当包含一个描述了为何版本不被支持以及服务器支持哪些协议的实体。
506Variant Also Negotiates 代表服务器存在内部配置错误:被请求的协商变元资源被配置为在透明内容协商中使用自己,因此在一个协商处理中不是一个合适的重点。
507Insufficient Storage 服务器无法存储完成请求所必须的内容。这个状况被认为是临时的。
509Bandwidth Limit Exceeded 服务器达到带宽限制。这不是一个官方的状态码,但是仍被广泛使用。
510Not Extended 获取资源所需要的策略并没有被满足。
600Unparseable Response Headers 源站没有返回响应头部,只返回实体内容。

 五、HTTP头信息

  在HTTP报文的请求头中,除了手动增加自定义属性到头信息中,还存在如下默认的属性:

  1. Host :主机ip地址或域名。
  2. User-Agent :客户端相关信息,如果操作系统、浏览器等信息。
  3. Accept :指定客户端可接收信息类型,如: image/jpg, text/html, application/json。
  4. Accept-Charset :客户端接受的字符集,如Igb2312、1s0-8859-1。
  5. Accept -Encoding :可接受的内容编码,如gzip。
  6. Accept - Language :可接受的语言,如Accept-Language :zh-cn。
  7. Authorization :客户端提供给服务端,进行权限认证的信息。
  8. Cookie :携带的cookie信息。
  9. Referer:当前文档的URL,表示即从哪个链接过来的。
  10. Content-Type:请求体内容类型,如content-Type: application/x-ww- form-urlencoded等,不同的文件格式通常标识不同,请参照HTTP content-type 对照表。
  11. Content - Length :指出报文中实体主体的字节大小。这个大小是包含了所有内容编码的。
  12. Cache -Control:用于指定所有缓存机制在整个请求/响应链中必须服从的指令。这些指令指定用于阻止缓存对请求或响应造成不利干扰的行为。常见的取值有private、no-cache、max-age、must-revalidate等,默认为private。

  与请求头信息对应的还有默认的响应头属性:

  1. Server :服务器名字。Servlet一般不设置这个值,而是由Web服务器自己设置。
  2. Date:当前的GMT时间。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。
  3. Expires:指定缓存过期时间。
  4. Set-Cookie :设置和页面关联的Cookie。Servlet不应使用response.setHeader("Set-Cookie", ...),而是应使用HttpServletResponse提供的专用方法addCookie。参见下文有关Cookie设置的讨论。
  5. Last-Modified:文档的最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个304。
  6. Content-Type:响应的类型和字符集。
  7. Content-Length:响应的内容长度。
  8. Content-Encoding:文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。
  9. Connection:如Keep-Alive,表示保持tcp连接不关闭 Location 指明重定向的位置,新的URL地址, 如304的情况。
  10. Location:表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。
  11. Allow:服务器支持哪些请求方法(如GET、POST等)。
  12. Refresh:表示浏览器应该在多少时间之后刷新文档,以秒计。除了刷新当前文档之外,你还可以通过setHeader("Refresh", "5; URL=http://host/path")让浏览器读取指定的页面。
  13. WWW-Authenticate:客户应该在Authorization头中提供什么类型的授权信息?在包含401(Unauthorized)状态行的应答中这个头是必需的。例如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"")。

六、浏览器表单编码

  浏览器端通过表单向服务器发生数据时,Form表单有一个enctype属性用于指定表单数据的编码方式,enctype值如下:

  1. application/x-www-urlencoded:表单提交的默认类型,当POST方式提交表单时,表单内容将被序列化为key1=val1&key2=val2&...的字符串形式放在请求体中。当GET方式提交时则会被放到url的?后面。
  2. boundary指定的随机字符串进行分割multipart/form-data:表示表单数据由多部份构成,包含文本数据和文件二进制数据,这个主要用来传输非文本内容(包含文件上传控件表单),表单内容被编码为一组Parts放到请求体中,每个Part对应一个表单控件信息,Part之间通过boundary指定的随机字符串进行分割。请求体中的数据格式如下:
<!--请求头中需要指定Content-Type为multipart/form-data,指定Part分割字符串boundary,该字符串必须以--开头,一般由浏览器自动生成-->
Content-Type: multipart/form-data; boundary=${Boundary}
 
<!--请求体内容格式举例-->
--${Boundary}                                         <!--每个Part的分隔符-->
Content-Disposition: form-data; name="name of file"   <!--表单控件name属性-->
Content-Type: application/octet-stream                <!--数据类型为stream,表示这是一个二进制流-->
                                                      <!--空行-->
bytes of file                                         <!--文件的二进制数据-->
--${Boundary}
Content-Disposition: form-data; name="name of pdf"; filename="pdf-file.pdf"  <!--表单控件name属性,上传文件的文件名-->
Content-Type: application/octet-stream  
 
bytes of pdf file
--${Boundary}
Content-Disposition: form-data; name="key"           <!--表单控件name属性-->
Content-Type: text/plain;charset=UTF-8               <!--表单数据类型为text,表示这是一个文本-->
 
text encoded in UTF-8                                <!--text文本数据,默认utf-8编码-->
--${Boundary}--

  3.text/palin:将表单数据原封不放入请求主体中,表示纯文本传输,空格转换为 “+” 加号,不对特殊字符进行编码。

 七、HTTP请求的过程

  1.  客户端应用构建请求报文;
  2. 检查是否可以从本地缓存中直接获取资源;
  3. 解析请求行,获取url和端口;
  4. 通过dns服务器获取IP地址;
  5. 客户端通过TCP协议与服务器建立连接;
  6. 发送HTTP请求;
  7. 服务器收到请求报文进行处理;
  8. 服务器返回响应报文;
  9. 客户端根据响应数据类型进行响应的处理:如果客户端是浏览器,响应的是html则会直接渲染,如果是文件则弹出下载窗口,如果是图片则直接显示等等;
  10. HTTP请求完成,关闭TCP连接。

 

posted @ 2023-06-12 16:34  我若安好,便是晴天  阅读(62)  评论(0编辑  收藏  举报