网络协议-应用层(HTTP/HTTPS)

·  阅读 775

认识HTTP

超文本传输协议(英语:Hyper Text Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。

设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法(所以又叫做超文本传输协议)。通过HTTP或者HTTPS协议请求的资源由统一资源标识符(Uniform Resource Identifiers,URI)来标识。目前使用最广泛的版本是1.1的版本,HTTP是基于TCP协议的,在1.1版本中是默认开启 Keep-Alive(下文会说到对应字段)的,所以不用每次发起HTTP请求都建立链接然后请求完成之后释放链接(这样可以做到节省资源的效果)

HTTP请求准备

首先第一步就是现根据URL通过DNS解析找到对应的IP地址,然后上文也说道了HTTP是基于TCP协议的所以拿到IP之后就开始建立链接,当链接建立成功至此HTTP的请求准备就做完了就可以发送数据了

报文格式

请求报文格式

Image From 第14讲 HTTP协议:看个新闻原来这么麻烦.png

响应报文格式

Image From 第14讲 HTTP协议:看个新闻原来这么麻烦.png

ABNF

上文分别列举了请求报文和响应报文的格式图,只能多基本上大多数的请求都是按照上面两个图片进行封装的,但是上面两个图的格式不是最近准的,最严谨的HTTP报文格式描述形式是ABNFRFC 5234中表明:ABNF用作internet中通信协议的定义语言,这里在补充一下 RFC: >RFC:请求意见稿(英语:Request for Comments,缩写:RFC),又翻译作意见征求意见请求请求评论是由互联网工程任务组(IETF)发布的一系列备忘录。文件收集了有关互联网相关信息,以及UNIX和互联网社群的软件文件,以编号排定。目前RFC文件是由互联网协会(ISOC)赞助发行。

比如:HTTP/1.1最早是在1997年的RFC 2068中记录的

  • ABNF核心规则 image.png
  • 报文格式
    HTTP-message = start-line *( header-field CRLF ) CRLF [ message-body ] 可以再 rfc7230找到相关标准如下图: image.png
    • start-line: image.png 如果是发送请求则start-line是请求行也就是 request-line如果是响应报文则是 status-line

    • request-line: image.png 翻译一下就是请求方式也就是 getpost等,SP就是一个空格,然后是请求的对象,就是对应的URL又是一个空格然后 http版本最后加一个回车换行
      例如:POST /address HTTP/1.1

    • status-line: image.png 翻译过来就是:http版本+空格+状态码+返回reason+回车换行

    • header-field: image.png 就是头信息中的键值对,*()表示有0个或者多个,然后每个后面都有个回车换行

    • message-body:
      请求体也就是返回信息的地方或者传递信息的地方

      不难发现ABNF翻译过来之后基本上和上图的格式差不太多

头部字段

  • User-Agent
    image.png 浏览器的身份标识字符串,就比如我很很多时候访问一个下载软件的网页同是一个下载按钮我们在Windows上下载下来的是.exe格式的文件在Mac上面下载下来的就是.dmg格式的文件,这个就是后端通过判断该字段识别到了系统信息然后选择对应的字符串下载

  • Host
    服务器域名、端口号

  • Date
    发送该消息的日期和时间

  • Referer
    表示浏览器所访问的前一个页面,多用在防盗链上面,比如你们自己服务器上面上传了很多自己的图片,然后又不希望这个图片被人拿到到处地方去使用,这个就可以加一个Referer,不是冲指定页面跳转过来的服务器就不返回图片资源就好

  • Content-Type:
    请求体类型,例如: image.png

  • **Content-Length ** 请求体长度

  • Accept.
    能够接受的响应内容类型

  • Accept-Charset.
    能够接受的字符集

  • Accept-Encoding
    能够接受的编码方式列表

  • Accept-Language
    能够接受的响应内容的自然语言列表
    例如:zh-CN,zh;q=0.9 这里需要注意的是这个 qq值越大,表示优先级越高,如果后面没有跟 q则说明q=1,如上 zh-CN的q值是1, zh的q值是0.9(注意分割符师逗号不是分号) Accept-CharsetAccept-Encoding都可能出现 q值其含义都是一样的

  • Range.
    仅请求某个实体的一部分,字节便宜以0开始

  • Connection.
    想要优先使用的链接类型,keep-alive,不会发送接收完毕马上断开连接,会在指定时间内没有请求才会断开连接

  • server
    服务器的名字

  • Last-Modified.
    锁清秋的对象的最后修改日期

  • Expires
    指定一个时间,超过改时间则认为该响应已经过期

  • Content-Disposition.
    一个可以让客户端下载文件并建议文件名的头部

  • Accept-Ranges
    服务器支持哪些种类的部分内容范围

  • Content-Range
    这条部分消息是属于完整消息的哪部分

  • Location
    用来进行重定向,或者在创建了某个新资源时使用,以前前后端没有分离之前比如写个登录页面登录的页面路由是 /login 登录完成需要跳转到首页路由是 /home,这个时候就可以用重定向,登录成功重定向到首页此时登录完成就可以直接跳转到首页

  • Origin
    发起一个针对跨域资源共享的请求Origin就是发起跨域请求的源地址,例如一个域名是tudou.com现在想访问一个tudou2.com域名下的东西此时就需要跨域访问,此时的Origin就等于tudou.com

  • Access-Control-Allow-Origin
    指定哪些网站可参与到跨来源资源共享,上文中如果客户端请求头中含有Origin但是服务器没有指定Access-Control-Allow-Origin(没有指定的情况下默认就是同域名访问)的情况下虽然最终请求的数据会下发到浏览器,但是浏览器发现并不支持跨域共享资源,或者当前域名不在跨域共享资源的设置范围内,则不会返回数据Access-Control-Allow-Origin主要是后端同学设置的如下:
    response.setHeader("Access-Control-Allow-Origin","http://www.tudou.com");这样上文中的tudou.com就能访问tudou2.com域名下的东西。

  • Cookie
    是浏览器保存在客户端硬盘上的,如果服务器返回Set-Cookie,浏览器就会将对应的Cookie存到本地,对应的有一个session,session是存储在服务器内容中的两者配合实现会话跟踪技术,例如登录成功后服务器就会将用户名和密码存到session对应的就会生成一个sessionId,然后将这个id返回给客户端,这个时候客户端每次像服务器发送请求在头信息中将sessionId赋值给cookie,这就有了登录的凭证实现了会话跟踪的技术。 (这里需要注意的是cookie在浏览器关闭的时候也就失效了而session默认的是半个小时失效当然服务器可以设置失效时间同时也可以直接让session失效)

  • Set-Cookie
    返回一个cookie让客户端保存

  • Cache-Control
    浏览器在请求一些资源的时候会将这些资源缓存到本地,然后下一次在请求这些资源的时候可以直接从本地读取显示。

    一般会缓存的情况是GET请求 + 静态资源(比如HTML、CSS、JS、图片等)
    windows上可以使用crtl+f5强制刷新,mac上使用command+shift+r

    上文说的缓存好像挺简单的一个东西其实缓存内部实现还是比较复杂的,我们可以看一下对应的响应头信息:

    • Pragma:作用类似于Cache-Control,HTTP/1.0的产物
    • Expires:缓存的过期时间(GMT格式时间),HTTP/1.0的产物
    • Cache-Control:设置缓存策略
      • no-storage:不缓存数据到本地
      • public:允许用户、代理服务器缓存数据到本地
      • private:只允许用户缓存数据到本地
      • max-age:缓存的有效时间(多长时间不过期),单位秒
        如果还在缓存的有效期内此时在发送请求,这个请求不会到服务器,会直接拿到本地的缓存内容返回,此时该请求还是会有响应头,不过此时的响应头是上一次请求的响应头并不是最新服务器返回的响应头如下图所示: image.png 但是如果有效期过了此时就会带着上一次请求返回的一些信息给到服务器,服务器根据这些信息判断资源是否被改动过,如果被改动了则返回最新的资源给到浏览器,如果没有改动过就会返回304告诉浏览器你可以继续使用缓存中的内容
      • no-cache:每次需要发请求给服务器询问缓存是否有变化,再来决定如何使用缓存
        上文说到过了有效期会发送请求到服务器询问资源是否有变化,但是如果是no-cache,则是每次发请求都会询问,没过期则用缓存中的内容过期了服务器给新内容
    • 优先级:Pragma > Cache-Control > Expires
    • Last-Modified:资源的最后一次修改时间
      主要用来做资源对比的
    • ETag:资源的唯一标识(根据文件内容计算出来的摘要值)
      主要用来做资源对比的
    • 优先级:ETag > Last-Modified

    再看对应的请求头

    • If-None-Match
      如果上一次的响应头中有ETag,就会将ETag的值作为请求头的值,上文说到服务器会对资源作对比就是那最新的资源生成一个摘要值然后和If-None-Match的值作对比如果相等说明资源并没有修改过所以浏览器可以使用缓存中的内容否则返回最新内容
    • If-Modified-Since
      如果上一次的响应头中没有ETag,有Last-Modified,就会将Last-Modified的值作为请求头的值 服务器会拿到该资源的最新修改时间和Last-Modified传过来的值作对比不同则返回304否则返回200并返回最新内容(需要注意的是Last-Modified是精确到秒的所以还是有可能修改了但是还是返回304可能会出现一秒内的误差,或者是修改时间变了其实内容并没有变的情况,所以建议使用ETag)

    缓存流程图: Image From 09_HTTP.png

状态码

RFC 2616 10.Status Code Definitions规范中定义,状态码指示HTTP请求是否已成功完成,状态码主要分为5类(注意一下是状态码范围并不是有那么多的状态码比如188就没有这个状态码):

  • 信息响应:100-199
    常用的状态码是100 Continue
    请求的初始部分已经被服务器收到,并且没有被服务器拒绝。客户端应该继续发送剩余的请求,如果请求已经完成,就忽略这个响应。 其实就是在请求一个资源之前先发送一个请求里面还有URL和请求体,服务器通过判断URL或者是请求体,来判断这个资源是否能给客户端,如果不能给的话直接返回错误码,如果可以则返回100,让客户继续发送请求体。主要用在客户端能判断到自己索要的资源极有可能被服务器拒绝的情况下使用会节省性能。
  • 成功响应:200~299
    常见状态码:200 请求成功
  • 重定向:300~399
    常见状态码:
    • 302 Found:
      请求的资源被暂时的移动到了由Location头部指定的URL上,具体的例子可以看上文说到请求头字段时候的举例
    • 304 Not Modified:
      说明无需再次传输请求的内容,也就是说可以使用缓存的内容。
      就比如一些静态文件:图片、js\css文件啊,第一次拉取此时会缓存到本地,如果再次拉取的时候服务器会判断如果服务器觉得你缓存中的东西没有变过还是最新的就不会再将对应的资源返回给客户端,而是返回 304的状态码这个时候客户端就会知道此时资源需要冲缓存中查找,当然还可以是客户端在请求头中写入If-Modified-SinceIf-None-Match,服务器通过这个两个字段来判断缓存是否过期
  • 客户端错误:400~499
    常见状态码:(返回4该范围的状态码一般都是客户端的问题了,当然后端也可以将后端的问题返回状态码是400多但是这种情况还是很少见的)
    • 400 Bad Request:由于语法无效,服务器无法理解该请求。例如上文说到的请求头格式如果没有按照上文的格式来,服务器就没办法解析你的请求头所以就会报错400,还有中可能就是服务器需要的参数发现在请求体中或者url中没有,这个时候后端同学就可以主动返回一个400给客户端。
    • 401 Unauthorized:由于缺乏目标资源要求的身份验证凭证。例如一些资源是需要用户登录成功根据用户的身份来返回的就是超管才会给你否则不给这个时候就会需要一个身份凭证,一般都是登录成功之后后端会返回一个token,如果在请求一些需要身份凭证的接口的时候就需要带上这个token,否则返回401
    • 404 Not Found:服务器端无法找到所请求的资源,例如服务器上有/hello还有/login,结果你非要访问/home这个时候就会提示404
    • 405 Method Not Allowed:服务器禁止了使用当前HTTP方法的请求
    • 406 Not Acceptable:服务器端无法提供与Accept-Charset以及Accept-Language指定的值相匹配的响应
    • 408 Request Timeout:服务器想要将没有在使用的连接关闭,有些服务器会在空闲的时候发送这种消息,表示想要关掉TCP链接
  • 服务器错误 :500~599
    常见错误码:
    • 500 Internal Server Error:所请求的服务器遇到意外的情况并阻止其执行请求,其实就是服务器崩溃了
    • 501 Not Implemented:请求的方法不被服务器支持,因此无法被处理
    • 502 Bad Gateway:作为网关或代理角色的服务器,从上游服务器(如tomcat)中接收到的响应是无效的
    • 503 Service Unavailable:服务器尚未处于可以接受请求的状态,通常造成这种情况的原因是由于服务器停机维护或者已超载

form提交

就比如下图(这里拿QQ的注册中心做示例): 截屏2022-01-29 上午10.30.06.png在看一下这里的源代码 截屏2022-01-29 上午10.41.07.png 这里就是一个表单提交。

表单提交支持get和post这个需要设置表单提交的method属性来确认是get请求还是post请求,其中比较重要的一个属性是 enctype,需要注意的是这个属性只有在 methodpost的时候才会生效,enctype的取值有以下两种:

  • application/x-www-form-urlencoded
    enctype的默认值就是这个,该值的作用主要是定义请求体重传递参数的一个格式以及字符的编码方式:用&分隔参数,用=分隔键和值,字符用URL编码方式进行编码如下图所示: 截屏2022-01-29 上午10.52.53.png

  • multipart/form-data
    需要注意的是文本上传必须选择这种类型,其他类型服务器接收到的可能只是文件的名称以及文件的格式接收不到客户端传递的文件二进制数据

    作用和上文中的一样的无非就是这里定义的请求体的格式和上文中的application/x-www-form-urlencoded 不同,如下图所示: 截屏2022-01-29 上午11.03.15.png,首先就是 content-type中除了声明了编码类型是multipart/form-data之外还声明了 boundary,然后下文中的请求体也被分成了一段一段的,然后细心的同学可能会发现每一段的分割就是用的 boundary来分割,无非就是在 boundary前面又多加了两个 -,然后最后一行又加了一个 boundary最后一行的 boundary前后都添加两个 -,这种格式的规定在 RFC 1521中都是有记录的可以查一下RFC 1521验证一下上文中的说法

    从这里就可以发现Content-type的不同对应传递给服务器的请求体编码格式可能就不同就如上文中的两种,所以在客户端发送给服务器数据的同时也必须告诉服务器客户端这里的编码这是是什么样的,服务器根据他支持的对应的编码格式来解析请求体中的数据。需要注意的点是我们经常在开发的过程中调试接口的时候就会收到一些接口的报错提示不支持某种格式的数据,就是应为服务器这边只支持application/x-www-form-urlencoded格式的解析没有做multipart/form-data 格式的解析,所以后端就没办法拿到准确的请求体数据这个时候就会报错,所以客户端在传参的时候可以和后端的同学确认一下他们支持的格式是哪个,然后前端就传递那种格式的数据。

认识HTTPS

HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS 在HTTP 的基础下加入SSL,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。这个系统提供了身份验证与加密通讯方法。它被广泛用于万维网上安全敏感的通讯,例如交易支付等方面

其实就是在HTTP的基础上将消息报文进行了加密传输,具体如何加密可参考常见的加密方式

HTTPS的默认端口号是443(HTTP是80)

SSL/TLS

TLS的前身是SSL,被叫做传输层安全性协议

他的作用其实就是将报文进行加密然后在给传输层进行传输。
所以我们大概也可以才到它主要作用在应用层和传输层之间如下图所示: Image From 11_HTTPS.png

HTTPS的通信过程

  1. 建立TCP链接
  2. 建立TLS链接
  3. HTTP请求和响应

其实就多了第二步,剩下和HTTP一样,多第二步的原因也是应为需要只要加密密钥证书等信息 image.png

TLS 1.2的链接

大致流程如下: Image From 11_HTTPS.png

  • 第一步:Client Hello
    1. TLS版本号
    2. 支持的加密组件(Cipher Suite)列表
      加密组件(Cipher Suite):指的是加密算法和密钥长度等
    3. 一个随机数
    抓包结果如下:

image.png

  • 第二步:Server Hello
    1. TLS版本号
    2. 选择的加密组件
      从客户端提供的加密组件列表中选择一个
    3. 一个随机数

image.png

  • 第三步:Certificate
    将证书给到客户端 image.png

  • 第四步:Server Key Exchange
    用以实现ECDHE算法的其中一个参数(Server Params)

    ECDHE是一种密钥交换算法(为了防止伪造,Server Params经过了服务器私钥签名) image.png

  • 第五步:Server Hello Done
    告诉客户端协商部分结束,到目前为止客户端和服务器通过明文共享了Client Random、Server Random、Server Params,而且客户端已经拿到了服务器的公钥证书,然后客户端就会检验证书的真实有效性

  • 第六步:Client Key Exchange
    证书验证成功后就会给服务器再发送一个用以实现ECDHE算法的另一个参数 image.png 此时客户端和服务器就都有了Server Params、Client Params,
    然后客户端和服务器都可以使用ECDHE算法根据Server Params、Client Params计算出一个新的随机密钥串:Pre-master secret
    然后结合Client Random、Server Random、Pre-master secret生成一个主密钥
    最后利用主密钥衍生出其他密钥:客户端发送用的会话密钥、服务器发送用的会话密钥等

  • 第七步:Change Cipher Spec
    告知服务器:之后的通信会采用计算出来的会话密钥进行加密

image.png

  • 第八步:Finished
    包含连接至今全部报文的整体校验值(摘要),加密之后发送给服务器
    然后服务器进行解密如果解密成功则这次握手是成功的 image.png
  • 第九步:Change Cipher Spec 同样的服务器告知客户端会话密钥 image.png
  • 第十步:Finished
    最后也是将全部报文的摘要用会话密钥加密后发送给客户端 如果客户端解密成功标识链接成功,接下来就是发送正文了
分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改