由浅入深了解超文本传输协议http

什么是超文本传输协议?

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

通过HTTP或HTTPS协议请求的资源由统一资源标识符(Uniform Resource Identifiers,URI)来标识。

协议概述

HTTP是一个客户端(client)和服务端(server)之间请求和应答的标准,通常使用TCP协议。通过使用浏览器、网络爬虫或者其他工具,客户端发起一个HTTP请求到服务器上的指定端口(默认端口为80)。我们称这个客户端为用户代理程序(user agent)。应答的服务器上存储着一些资源,比如HTML文件或者图像。我们称这个应答服务器为源服务器(origin server)。在用户代理或者源服务器中间可能存在多个“中间层”,比如代理服务器、网关或者隧道。

通常,由HTTP客户端(client)发起一个请求,创建一个到服务器(server)指定端口的TCP连接。HTTP服务器则在那个端口监听客户端的请求。一旦收到请求,服务器会向客户端返回一个状态,比如“HTTP/1.1 200 OK”,以及返回的内容,如请求的文件、错误信息或者其它信息。

请求方法

HTTP/1.1协议中一共定义了八种方法(也叫“动作”)来以不同方式操作指定的资源:

Get

向指定的资源发出“显示”请求。使用GET方法应该只用在读取资料,而不应当被用于产生“副作用”的操作中。

Post

向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)。数据被包含在请求本文中。这个请求可能会创建新的资源或修改现有资源,或二者皆有。每次提交,表单的数据被浏览器用编码到HTTP请求的body里。浏览器发出的POST请求的body主要有两种格式,一种是application/x-www-form-urlencoded用来传输简单的数据,另外一种是传文件,会采用multipart/form-data格式。

Put

向指定资源位置上传其最新内容。一般用作修改资源内容

Delete

请求服务器删除Request-URI所标识的资源。

Head

与GET方法一样,都是向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分。它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中“关于该资源的信息”(元信息或称元数据)。

Trace

回显服务器收到的请求,主要用于测试或诊断。

Options

这个方法可使服务器传回该资源所支持的所有HTTP请求方法。用’*'来代替资源名称,向Web服务器发送OPTIONS请求,可以测试服务器功能是否正常运作

Connect

HTTP/1.1协议中预留给能够将连接改为隧道方式的代理服务器。通常用于SSL加密服务器的链接(经由非加密的HTTP代理服务器)。

方法名称是区分大小写的。HTTP服务器至少应该实现GET和HEAD方法,其他方法都是可选的。对于GET和HEAD方法而言,除了进行获取资源信息外,这些请求不应当再有其他意义。也就是说,这些方法应当被认为是“安全的”。 客户端可能会使用其他“非安全”方法,例如POST,PUT及DELETE,应该以特殊的方式(通常是按钮而不是超链接)告知客户可能的后果(例如一个按钮控制的资金交易),或请求的操作可能是不安全的(例如某个文件将被上传或删除)。

HTTP 流

当客户端想要和服务端进行信息交互时,过程表现为下面几步:

  1. 打开一个TCP连接:TCP连接被用来发送一条或者多条请求,以及接受响应消息。

  2. 发送一个 HTTP 报文:HTTP 报文(在 HTTP/2 之前)是语义可读的。

    GET / HTTP/1.1
    Host: developer.mozilla.org
    Accept-Language: fr
    
  3. 读取服务端返回的报文消息:

    HTTP/1.1 200 OK
    Date: Sat, 09 Oct 2010 14:28:02 GMT
    Server: Apache
    Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT
    ETag: "51142bc1-7449-479b075b2891b"
    Accept-Ranges: bytes
    Content-Length: 29769
    Content-Type: text/html
    
    <!DOCTYPE html... (here comes the 29769 bytes of the requested web page)
    
  4. 关闭连接或者为后续请求重用连接。

HTTP 报文

HTTP/1.1 以及更早的 HTTP 协议报文都是语义可读的。

有两种 HTTP 报文的类型,请求与响应,每种都有其特定的格式。

请求

在这里插入图片描述

请求元素:

  • HTTP的请求方法(Method):经常是由一个动词GET、POST或者名词OPTIONS、HEAD来定义客户端的动作行为。
  • 要获取的资源的路径(Path):通常是上下文中就很明显的元素资源的URL,它没有protocol(http://),domain(developer.mozilla.org)或是TCP的port(80)。
  • HTTP协议的版本号(Version of the protocol)。
  • 为服务端表达其他信息的可选标头(Headers)。
  • 对于一些像POST这样的方法,报文的主体(body)就包含了发送的资源,这与响应报文的主体类似。

响应

在这里插入图片描述

响应元素:

  • HTTP协议版本号(Version of the protocol)。
  • 状态码(Status code):来告知对应请求执行成功或失败,以及失败的原因。
  • 状态信息(Status message):这个信息是非权威的状态码描述信息,可以由服务端自行设定。
  • HTTP标头(Headers):与请求标头类似。
  • 可选项,比起请求报文,响应报文中更常见地包含获取资源的主体。

HTTP 标头(header)

常见的 request 中的标头

Accept
  • Accept: text/html 浏览器可以接受服务器回发的类型为text/html
  • Accecpt: */* 浏览器可以接受所有类型(通常是这个)。
Accept-Encoding
  • Accept-Encoding: gzip, deflate 浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip, deflate)。
Accept-Language
  • 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 浏览器申明自己接收的语言。(q代表权重,数值越大则代表越优先选择)
Connection
  • Connection: keep-alive 当一个网页打开完成后,客户端和服务端之间用于传输 HTTP 数据的 TCP 连接不会关闭,如果客户端再次访问这个服务器的网页,会继续使用这一条已经建立的连接。
  • Connection: close 代表一个 Request 完成后,客户端和服务端之间用于传输 HTTP 数据的 TCP 连接关闭,当客户端再次发送 Request,需要重新建立 TCP 连接。
Host(发送请求时,该header是必须的)
  • Host: www.example.com 主要用于指定被请求资源的 Internet 主机和端口号,它通常从 HTTP URL中提取出来。
Referer
  • Referer: <url> 包含了当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的。
User-Agent
  • User-Agent: <product> / <product-version> <comment> 包含了一个特征字符串,用来让网络协议的对端来识别发起请求的用户代理软件的应用类型、操作系统、软件开发商以及版本号。
Cache-Control
  • Cache-Control: private 默认为private,响应只能够作为私有的缓存,不能在用户间共享
  • Cache-Control: public 响应会被缓存,并且在多用户之间共享。正常情况,如果要求 HTTP 认证,响应就会自动设置为 private。
  • Cache-Control: no-cache 响应不会被缓存,而是实时向服务器请求资源。
  • Cache-Control: max-age=10 设置缓存的最大有效时间,但是这个参数定义的时间大小。单位:秒。
  • Cache-Control: no-store 任何条件下,响应都不会被缓存,并且不会被写入到客户端的磁盘里。
Cookie

含有先前由服务端通过Set-Cookie投放或者 JavaScript 的Document.cookie设置的,然后存储到客户端的 HTTP cookie。

Range(用于断点续传)
  • Range: bytes=0-5 指定第一个字节的位置和最后一个字节的位置。用户告诉服务器自己想取对象的哪部分。

常见的 response 中的标头

Cache-Control(对应请求的Cache-Control)
  • Cache-Control: private 默认为private,响应只能够作为私有的缓存,不能在用户间共享
  • Cache-Control: public 响应会被缓存,并且在多用户之间共享。正常情况,如果要求 HTTP 认证,响应就会自动设置为 private。
  • Cache-Control: no-cache 响应不会被缓存,而是实时向服务器请求资源。
  • Cache-Control: max-age=10 设置缓存的最大有效时间,但是这个参数定义的时间大小。单位:秒。
  • Cache-Control: no-store 任何条件下,响应都不会被缓存,并且不会被写入到客户端的磁盘里。
Content-Type
  • Content-Type: text/html;charset=UTF-8 告诉客户端,资源文件的类型,还有字符编码,客户端通过utf-8对资源进行解码,然后对资源进行 html 解析。通常我们会看到有些网站是乱码的,往往就是服务端没有返回正确的编码。
Content-Encoding
  • Content-Encoding: gzip 告诉客户端,服务端发送的资源是采用 gzip 编码的,客户端收到该消息后,应该采用 gzip 对资源进行解码。
Date
  • Date: Tue, 03 Apr 2018 03:52:28 GMT 这个是服务端发送资源时的服务器时间,GMT是格林尼治所在地的标准时间。
Server
  • Server: Tengine/1.4.6 这个是服务器和相对应的版本,只是告诉客户端服务器信息。
Transfer-Encoding
  • Transfer-Encoding:chunked 告诉客户端,服务端发送的资源是分块发送的。一般分块发送的资源都是服务器动态生成的,在发送时还不知道发送资源的大小,所以采用分块发送,每一块都是独立的,独立的块都能标示自己的长度,最后一块都是0长度的,当客户端读到这个0长度的块时,就可以确定资源已经传输完了。
Expires
  • Expires: Sun, 1 Jan 2000 01:00:00 GMT 这个响应头也跟缓存有关,告诉客户端在这个时间前,可以直接访问缓存副本,但是客户端和服务端的时间不一定会都是相同的,如果时间不同就会导致问题。
Last-Modified
  • Last-Modified: Dec, 26 Dec 2015 17:30:00 GMT 所请求的对象的最后修改日期。
Connection
  • Connection: keep-alive 回应客户端的Connection: keep-alive,告诉客户端服务器的 TCP 连接也是一个厂链接,客户端可以继续使用这个 TCP 连接发送 HTTP 请求。
ETag
  • ETag: "737060cd8c284d8af7ad3082f209582d" 就是一个对象(比如URL)的标志值,就一个对象而言,比如一个 html 文件,如果被修改了,其 ETag 也应该会被修改,主要供缓存来识别文件是否被修改。
Refresh
  • Refresh: 5; url=http://www.baidu.com 用于重定向,或者当一个新的资源被创建时。默认会在5秒后刷新重定向。
Content-Range
  • Content-Range: bytes 200-1000/67589 显示的是一个数据片段在整个文件中的位置

无状态、cookie、session、Token

什么是无状态

在同一个连接中,两个执行成功的请求之间是没有关系的。这就会带来一个问题,用户没有办法在同一个网站中进行连续的交互。比如在一个电商网站里,用户想分两次想把某个商品加入到购物车中,这两次添加商品的操作是没有关联的,服务端其实是没办法知道这两次添加商品其实都是同一个用户在同一次添加的。

使用 HTTP Cookie 可以解决这个问题。

无状态的好处

减少服务端的存储开销:服务端不需要存储请求的状态信息。

无状态的坏处

服务器没有记忆能力,无法完成一些需要关联性的操作。如同一用户两次往购物车添加商品。

Cookie

HTTP Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据。浏览器会存储 cookie 并在下次向同一服务器再发起请求时携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器——如保持用户登录状态。Cookie使基于无状态的HTTP协议记录稳定的状态信息成为了可能。

服务器使用Set-Cookie向client发送Cookie信息,可能像这样:

Set-Cookie: <cookie-name>=<cookie-value>

事例表明服务器告知客户端存储一对cookie:

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

接下来,对该服务器发起的每一次新请求,浏览器都会将之前保存的Cookie信息通过header再发送给服务器:

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
限制访问Cookie

有两种方法可以确保Cookie被安全发送,并且不会被意外的参与者或脚本访问:Secure属性和HttpOnly属性。

Secure:有此标记的Cookie只应通过被HTTPS协议加密过的请求发送给服务器。它永远不会使用不安全的HTTP发送(本地主机除外),不安全的站点(在URL中带有http:)无法使用带有Secure属性的cookie。但是,Secure不会阻止对cookie中敏感信息的访问。例如,有权访问客户端硬盘的人可以读取和修改它。

HttpOnly:JavaScript的Document.cookieAPI无法访问带有HttpOnly属性的cookie;此类cookie仅作用于服务器。

Session

基于cookie实现的,session存储在服务器端,sessionId会被存储到客户端的cookie中。

  1. 用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的Session。
  2. 请求返回时将此Session的唯一标识信息SessionId返回给浏览器
  3. 浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名
  4. 当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。
安全性不同

Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的。

存值的数据类型不同

Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型。

有效期不同

Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。

存储大小不同

单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源。

Token

token的身份验证流程:

  1. client使用用户名和密码请求登录
  2. server收到请求,去验证用户名与密码
  3. 验证成功后,server会签发一个token并下发给client
  4. client接收到token,会将token存储起来,如:存到cookie或localStorage
  5. client每次向server发送请求资源都携带token
  6. server接收到来自client的token并且验证它。

Tips

服务端不需要存储token,只需要使用固定的算法解析token。利用解析Token的资源换取存储Token的存储空间。以时间换空间,减轻服务器的压力。

状态码

常见的状态码

状态码英文名称中文描述
200OK请求成功
301Moved Permanently资源(网页等)被永久转移到其他URL
400Bad Request客户端请求的语法错误,服务器无法解析
404Not Found请求的资源(网页等)不存在
500Internal Server Error服务器内部错误

状态码分类

分类描述
1xx信息,服务器收到请求,需要请求者继续进行操作
2xx成功,操作被成功接受并处理
3xx重定向,需要进一步的操作以完成请求
4xx客户端错误,请求包含语法错误或无法完成请求
5xx服务器错误,服务器在处理请求的过程中发生了错误

浏览器同源策略

同源的定义

如果两个URL的协议端口主机都相同的,那么这两个URL同源。

跨域资源共享 CORS

一种基于HTTP头的机制,该机制通过允许服务器标示除了它自己以外的其它源(域、协议或端口),使得浏览器允许这些源访问加载自己的资源。

对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(例如 CookieHTTP 认证相关数据)。

预检请求preflight request

“需预检的请求”要求必须首先使用OPTIONS发起一个预检请求到服务器,以获知服务器是否允许该实际请求。“预检请求”的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

附带身份凭证的请求

在响应附带身份凭证的请求时:

  • 服务器不能Access-Control-Allow-Origin的值设为通配符“*”,而应将其设置为特定的域,如:Access-Control-Allow-Origin: https://example.com
  • 服务器不能Access-Control-Allow-Headers的值设为通配符“*”,而应将其设置为标头(headers)名称的列表,如:Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
  • 服务器不能Access-Control-Allow-Methods的值设为通配符“*”,而应将其设置为特定请求方法名称的列表,如:Access-Control-Allow-Methods: POST, GET

HTTP Response Header 字段

header keyheader valuedescribe
Access-Control-Allow-Origin<origin> | *允许浏览器访问的资源列表
Access-Control-Allow-Headers<header-name>[, <header-name>]*允许浏览器访问的header列表
Access-Control-Allow-Methods<method>[, <method>]*指定访问资源时允许使用的请求方法
Access-Control-Max-Age<delta-seconds>指定preflight预检请求能够被缓存多久
Access-Control-Expose-Headers<header-name>[, <header-name>]*允许浏览器访问的额外header列表
Access-Control-Allow-Credentialstrue指定浏览器的credentials是否允许浏览器读取response的内容
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值