一文打尽HTTP

1,038 阅读25分钟

一文打尽Http

本篇主要为学习笔记,涉及到HTTP/1、HTTP/2、CSP、RestfulApi、跨域等等内容。

从输入url到返回HTTP响应,浏览器的处理流程?

HTTP-1.0

依赖其他协议

HTTP协议依赖其它协议实现,如IP、TCP、UDP、DNS、ARP协议等

  • TCP/IP,分层协议

    • 应用层:ftp、dns、http
    • 传输层:tcp、udp
    • 网络层:数据包是网络传输的最小数据单位
    • 链路层:用来处理连接网络的硬件部分
  • ARP协议,将IP转为MAC

  • DNS协议,将域名转为IP

HTTP报文依赖上述协议进行传入,其传输过程如下:

在传输过程中,有一个很重要的的概念,什么是TCP三次握手?

从更广泛的角度来看,当浏览器输入url后,各类协议如何协同工作?

还有一个非常重要的概念::

  • url是统一资源定位器,如http://b.edu.51cto.com
  • uri统一资源标志符,如ftp://abc/a.txt

HTTP的应用

HTTP主要用于客户端和服务端之间的通信通信数据转发服务,重点了解下通信数据转发应用:

  • 代理,接受客户端发送的请求并转发给服务器,接受服务器的响应并转发给客户端

  • 网关,接收客户端的请求,就像自己拥有资源一样,对请求进行处理(转发局域网内其他服务器的数据,局域通信的协议可以不是http)

  • 隧道,相隔甚远的客户端和服务器之间进行中转,并保持双方通信连接的应用程序

代理的意义:缓存代理(将服务端资源缓存在代理服务器),透明代理(不对报文进行任何加工处理),非透明代理(对报文内容进行处理)

网关的意义:将非HTTP服务转为HTTP服务,提高通信的安全性?

隧道的意义:隧道可按照要求建立一条与其他服务器的通信线路,使用SSL等加密手段进行通信;隧道的目的是确保客户端能够与服务器进行安全的通信;隧道本身不会去解析HTTP请求,请求和响应原样传输;隧道会在通信双方断开连接时结束。

缓存是指代理服务器或客户端本地磁盘内保存的资源副本,利用缓存可以减少对源服务器的访问,也就节省了通信流量和时间。缓存可以设置有效时间,如果资源过期则重新请求。

HTTP特点和缺陷

  • 无状态

不对请求和响应之间的通信状态(如登录态)保存,不做持久化处理,好处就是简单!

  • 无连接

请求完成后断开tcp连接,好处就是减少服务器CPU和内存消耗

随着Web越来越复杂,用户期待更好的体验,如速度更快、保留登录态等等,于是就需要进行改进。

如何要保留用户的状态(如登录态),于是有了Cookie技术:

TCP的连接过程是相当复杂的,需要经历3次握手才能传递数据。能不能节省握手时间,于是就有了持久连接技术:

HTTP/1.1开始支持持久化连接,且默认为持久连接;持久连接使用字段:connection:keep-alive;Chrome为了进一步提升速度,会为单个域名开启6个线程去请求资源。

传统的HTTP是请求/响应模式的,单个请求必须要等待响应完成后才能继续其它请求。如何节省请求等待时间,于是就有了管线化技术:

管线化可以克服同域并行请求限制带来的阻塞,把所有请求一起发给服务器,服务器按顺序响应(依赖于持久连接技术)。

HTTP报文

学习HTTP必须要了解报文,透过报文结构可以了解请求/响应附加的各种信息,如:

  • 实体类型,请求数据的类型multipart/form-data、application/json

  • 获取部分内容的范围请求(断点恢复下载),设定获取资源范围,Range: bytes=5001-10000

  • 内容协商,客户端和服务端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源,如中英文界面:Accept、Accept-Charset、Accept-Encoding、Accept-Language、Content-Language

  • 缓存控制信息,如Cache-Control、Expires

HTTP请求报文

HTTP响应报文

HTTP报文结构

HTTP的请求方法: get/post/put/delete/head/option/trace/connect

业务中常常使用Post和Get,他们有什么区别?

1. get在浏览器回退是无害的,而post会再次请求
2. get请求的url地址可以被收藏,而post不可以?
3. get请求浏览器会主动缓存,而post不会,post需要手动使用localStorage等
4. get只支持URI编码,而post支持多种编码形式
5. get请求参数会被完整的保留在浏览器历史记录中,而post中的参数不会被保留
6. get请求携带的数据长度有限制,而post没有限制
7. get没有post安全,因为参数直接在url中,所以不能传递敏感信息
8. get参数通过url传递,而post通过请求体(request Body)

HTTP的状态码:

200,请求被服务器正常处理
204,请求成功,但是响应报文不含实体主体部分,收到204响应,浏览器页面不发生更新。【应用:一般在只需要从客户端往服务器发送信息,而对客户端不需要发送新信息内容的情况下使用】
206,客户端进行范围请求,服务器成功处理并返回有Content-Range指定范围的实体内容
301,永久性重定向。表示请求的资源被分配到新的URI上,以后应使用资源现在所指的URI。如果保存了书签,打开后依就会重定向(浏览器记住了重定向地址)【应用:res.location + res.sendStatus 配合使用等价于 res.redirect,重定向】
302,临时重定向,请求的资源被分配到新的URI上,希望用户本次使用新的URI访问(永久重定向时,即使修改重启了服务端源码,chrome浏览器依旧进行重定向跳转)
303,同302,但是要求指定客户端使用get方法请求新的URI
304,客户端发送附带条件的请求,如果为满足条件则返回304,满足则允许访问
307,与302相同,禁止从post请求变成get请求??
400,请求报文中存在语法错误,需要修改请求的内容后再次发送请求。浏览器会像200一样对待该状态码?(200如何处理的?)
401,请求需要通过http认证(BASIC认证,DIGEST认证),如果携带认证信息依就返回401则表示认证失败
403,请求访问的资源被服务器拒绝
404,服务器无法找到请求的资源,或者服务端拒绝请求且不想说明理由时使用。
500,服务端在执行请求时发生错误,可能web应用中存在的bug或临时故障
503,服务器处于超负载或者正在进行停机维护,无法处理请求

HTTP首部字段:

首部字段根据类型或缓存行为进行分类:

通用首部字段、请求首部字段、响应首部字段、实体首部字段 首部字段根据缓存行为分为两中类型,端到端首部字段(请求响应的最终接收目标)、逐跳首部字段(会因通过缓存或代理服务器不再转发,在HTTP/1.1后必须配合connection才能使用!)

# 客户端请求首部
GET / HTTP/1.1
Upgrade: HTTP/1.1
Connection: Upgrade

# 经过代理服务器后发送给Web服务器的首部
GET / HTTP/1.1

通用首部字段

请求首部字段

响应首部字段

实体首部字段

逐跳首部字段

通用首部字段详细介绍:

  • Cache-Control:控制缓存逻辑

    • public,响应可以被任何对象缓存(代理服务器、客户端)
    • private,响应只能被发起请求的客户缓存,不能被作为共享缓存(代理服务器)
    • no-cache,缓存资源,每次必须验证才可以被使用
    • no-store,不缓存任何内容
    • no-transform,不得对资源进行转换或转变。Content-Encoding、Content-Range、Content-Type等HTTP头不能由代理修改
    • max-age,设置缓存存储的最大周期
    • s-maxage,缓存服务器使用,缓存时间
    • max-stale,发起请求携带,即使缓存过期,在statle时间内还是可以使用缓存
    • must-revalidate,缓存max-age过期后,必须去服务端获取新的资源
    • proxy-revalidate,缓存服务器使用,效果同上
  • Connection:管理持久链接,配合逐跳首部字段使用

    • close,表明客户端或服务器想要关闭该网络连接
    • keep-alive,表明客户端想要保持该网络持久连接
  • pragma:不再推荐使用,与cache-control功能基本相同

  • Date:报文创建的日期和事件

  • trailer:待查询

  • transfer-encoding:逐跳传输消息首部,用于指定编码形式

    • chunked
    • compress
    • deflate
    • gzip
    • identity
  • upgrade:询问服务器是否支持其他协议,或者http更高协议??需要配合connection使用??

  • via:追踪客户端和服务端之间请求响应报文的传输路径,避免循环请求

  • warning: 报文存在的问题,部分警告码只能用于缓存代理服务器的响应报文

请求首部字段详细介绍

从客户端发出,用于补充请求的附加信息、客户端信息、对响应内容相关的优先级等

  • Accept,告知服务器,用户(或代理)能够处理的媒体类型及媒体类型的相对优先级,如Accept: text/plain; 1=0.3, text/html

  • Accept-Charset,告知服务器用户(或代理)支持的字符集及字符集的相对优先顺序,如Accept-Charset:utf-8,iso-8859-1;q=0.5

    Content-Type响应字段返回服务器的选择,如Content-Type: text/html; charset=utf-8

  • Accept-Encoding,告知服务器用户(或代理)支持的内容编码及内容的编码的优先级顺序。如Accept-Encoding:gzip、compress、deflate、identity

    Content-Encoding响应字段返回服务器的选择,如Content-Encoding: gzip

  • Accept-Language,告知服务器用户代理能够处理的自然语言集(中文或英文)。如Accept-Language: en-US,en;q=0.5

    Content-Language响应字段返回服务器的选择,如Content-Language: de-DE

  • Authorization,告知服务器用于验证用户身份的凭证,如Authorization: Basic abcdefg

  • Expect: 服务器只有满足此期望条件情况下才能妥善地处理请求。如Expect:100-continue(客户端要发送一个体积很大的消息体),等待状态码100后再发送消息体?

  • Form,电子邮箱

  • Host,虚拟主机运行在同一个ip上,使用此字段加以区分

  • If-Match,条件请求,服务端接受附带条件的请求后,只有判断为真时才执行请求。(if-match,资源ETag值相同)

  • if-Modified-Since,资源更新时间;;;;如果资源未更新返回状态码304Not Modified

  • if-None-Match,与if-Match相反

  • If-Range,若字段值与Etag或更新日期匹配,则继续作为范围请求。配合Range字段一起使用。若不一致则忽略返回,返回全部资源。(节约请求次数???)

  • Max-Forwards,设定请求被代理服务器转发的次数。

  • proxy-Authorization

  • Range,指定获取资源的范围,如Range: bytes=5001-10000(成功返回206,失败返回200+全部资源)

  • Referer,告诉服务器请求的原始资源的URI,常用于防盗链。

  • TE,告诉服务端客户端能够响应的传输编码方式及相对优先级,与Accept-Encoding功能很相像?

  • userAgent:将创建请求的浏览器和用户代理名称等信息传达给服务器。

响应首部字段详细介绍:

用于补充响应的附加信息、服务端信息、以及对客户端的附加要求等信息。

  • Accept-Ranges: bytes可处理范围请求,none不可处理范围请求

  • Age,源服务器在多久前创建了响应,字段值为秒。???

  • Etag,实体标识,uri相同时,借助etag区分文件

    • 强Etag,不论实体发生多么细微的变化都会改变其值。如Etag:usagi-1234
    • 弱Etag,用于提示资源是否相同。只有资源发生根本改变,产生差异时才会改变ETag值。
  • Location,将响应接收方引导到某个与请求URI位置不同的资源,基本上配合3XX:Redirection,进行重定向,。

  • Proxy-Authenticate,

  • Retry-After,高知客户端应该在多久之后再次发送请求。配合状态码503Service Unavailable。或3XX Redirect一起使用。可以指定具体日期,或者创建响应后的秒数

  • Server,告知客户端服务器上安装的http服务程序信息,如Server:Apache/2.2.6(Unix) PHP/5.2.5

  • Vary

  • www-Authenticate

实体首部字段详细介绍

请求报文和响应报文中实体部分使用的首部,用于补充内容的更新时间等与实体相关的信息

  • Allow,GET/HEAD,通知客户端,只接受指定方法
  • Content-Encoding:端到端首部字段(与transfer-encoding功能类似),实体内容编码方式。
  • Content-Language:zh-CN,通知客户端,实体所使用的自然语言(中文或英文)
  • Content-Length:实体主体部分的大小
  • Content-Location,
  • Content-MD5,报文主体生成MD5编码,服务端使用相同算法计算,进行比较。(但是无法意识到报文主体是否被篡改????)【主要用于判断报文主体的有效性?】
  • Content-Range,针对范围请求,返回响应时使用Content-Range指明实体的范围
  • Content-Type,实体主体内对象的媒体类型,如text/html;application/x-www-form-urlencoded
  • Exprires,指明资源失效的日期。(如果同时又max-age字段,则优先处理max-age字段。)
  • last-Modified,指明资源最终修改的时间。

Cookie字段详细介绍

set-cookie,服务端下发cookie,set-Cookie:status=enable; expires=Tue, 05 Jul 2011 07:26:31 GMT path=/ domain=.hack.jp secure httponly

  • expires,max-age指定cookie有效期
  • path指定cookie的范围
  • domain指定域名
  • secure指定https链接才发送cookie
  • httponly指定js无法获得cookie
  • cookie。服务端请求时候自动携带cookie
  • 关闭浏览器后,未设置时间的cookie自动清除【会话时效】

http认证机制

认证信息的方式通常有:密码,动态令牌、数字证书、生物认证、IC卡。HTTP如何认证?

HTTP使用表单携带密码进行认证,借助cookie、session、jwt等方式管理状态,具体流程如下:

注:服务端如何安全保存密码?密码加盐添加额外信息,再使用散列函数进行处理,最后存储散列值!

  • cookie技术

存放在客户端,主要由服务器下发set-cookie。cookie符合同源策略,每次请求时会自动携带。cookie有大小限制,单个限制3kb。

  • session

存放在服务端,用于记录用户状态。依赖于cookie技术(下发sessionIdcookie)。当访客较多时,占用服务端性能。

  • JWT

session-cookie技术,session保存在服务端安全,可以手动清除session,兼容性好。但是在跨域场景下不够友好,基于cookie技术很容易被CRSF(跨站请求伪造)。

JWT技术,服务端将信息进行加密(还会设置验签)下发给客户端,客户端存储在sessionStorage或localStorage中,每次请求中Authorization字段携带jwt信息,服务端验证通过后返回信息。

HTTPS安全性

理解网络安全:

  • 网络信息安全与保密的三个要素:保密性、完整性、可用性
  • 对称加密:用同一个密钥进行加密和解密
  • 非对称加密:加解密使用一对唯一性密钥(公钥和私钥)。公钥加密、私钥解密称为解密;私钥加密、公钥解密称为签名和验证签名。(rsa,dsa)
  • 单向加密:不可逆的加密,定长输出。(md5、sha1,sha256)

HTTP的缺点

  • 通信使用明文,内容可能被监听;
  • 不验证通信方的身份,可能遭遇伪装攻击;
  • 无法证明报文完整性,有可能被篡改。

HTTPS借助SSL或TLS协议,加密HTTP通信内容,基于证书服务实现身份认证,即http + 加密 + 认证 + 完整性保护 === https,但是,加密和解密消耗计算资源,也会使通信变慢。

https加密原理

共享密钥加密:

公私钥加密:

混合加密机制:

引入证书证明公钥是正确的:

了解了加解密原理,了解了证书原理,HTTPS建立通信的全过程:

AJAX等技术

传统的HTTP通信过程,每次请求时都返回整个页面,无法做到局部更新:

AJAX技术,使用js执行异步网路请求,可以实现局部更新:

Comet技术,收到请求后服务端会等待内容更新,再返回响应,实现了服务端推送,但是为了维持链接,需要消耗更多的资源:

轮询效率低,所以有了全双工通信websocket,其最常用场景---聊天软件

前端安全

了解浏览器的CSP/同源策略,了解常见的攻击方式,保证业务安全。

前端主要攻击形式:XSS跨站脚本攻击、SQL注入、CSRF跨站请求伪造。

Content-Security-Policy

内容安全策略,用于减弱并削弱某些特定类型攻击,包括跨站脚本和数据注入攻击。CSP向后兼容,网页默认会使用同源策略确保安全。

如何使用:

一是可以由服务端下发,而是可以通过meta设置<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

防御原理:

指定浏览器可执行js的来源,避免xss脚本攻击;指定资源加载域;指定资源加载的协议,如强制HTTPS协议。

常用字段`default-src/script-src/style-src/img-src/self

跨域及同源策略

同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互,同源的定义是:协议/域名/端口 相同。

不符合同源策略的请求,如何实现实现通信呢?即如何跨域?

跨域限制是浏览器的行为,可以给chrome浏览器设置--disable-web-security --user-data-dir=C:\MyChromeDevUserData,即可轻松实现跨域,设置教程:www.cnblogs.com/laden666666…

除了上述hack方法,还有如下正规的途径。

CORS跨域资源共享

Ajax符合同源策略,如何突破ajax跨域限制?即CORS方法!

  • 简单请求的条件

    • 请求方法只能是:HEAD、GET、POST
    • Header字段是能有:Accept、Accept-Language、Content-Language、Content-Type(application/x-www-form-urlencodedmultipart/form-datatext/plain)
  • cors请求流程

    • 请求携带Origin字段,说明本次请求来自哪个源(协议+域名+端口)
    • 响应会包含字段Access-Control-Allow-Origin等
  • 预请求

    • 对于非简单请求,在正式请求之前会预请求

    • 使用OPTIONS方法,询问浏览器是否允许跨源请求

      OPTIONS /cors HTTP/1.1
      Origin: http://api.bob.com
      Access-Control-Request-Method: PUT
      Access-Control-Request-Headers: X-Custom-Header
      

jsonp跨域请求

Cors比jsonp更强大,支持所有请求类型;而jsonp只支持get请求,但是jsonp支持老版本浏览器,兼容性更好。JSOP的实现代码如下:

function jsonp(src, onsuccess, onerror) {
    const callback = 'callback_' + Math.random().toString().substr(1, 6)
    window[callback] = function () {
        onsuccess && onsuccess.apply(null, arguments)
    }

    const script = document.createElement('script')
    script.setAttribute("type","text/javascript")
    script.setAttribute('src', `${src}?jsonp=${callback}`)
    script.async = true
    script.onload = script.onreadstatechange = function () {
        if (!script.readystate && /complete|loaded/.test(script.readystate)) {
            script.onload = script.onreadstatechange = null
            if (script.parentNode) {
                script.parentNode.removeChild(script)
            }
            window[callback] = null
        }
    }
    script.onerror = function () {
        onerror && onerror()
    }

    document.appendChild(script)
}

WebSocket

Webscoket全双工通信,事件驱动响应,支持跨域通信。

// 客户端
let ws = new WebSocket('ws://localhost:3000/')
ws.onopen = function() {
    ws.send('Hello!');
}
ws.onmessage = function(msg) {
    console.log('get Message:', msg.data); 
}

// 服务端
const WebSocket = require('ws')
const wss = new WebSocket.Server({port: 3000})
wss.on('connection', function(ws) {
  ws.on('message', function (message) {
    ws.send(`${message}-server`, err => {
      if (err) {
        console.log(err)
      }
    })
  })
})

XSS--跨站脚本攻击

如下图演示的攻击原理,上图为正常渲染,下图为攻击方式:

XSS脚本危害非常大,嵌入了可执行脚本可以做很多事情:

  • 获取页面数据
  • 获取cookies
  • 劫持前端逻辑
  • 发送请求

XSS根据存储方式分为:

  • 反射型:url参数直接注入
  • 存储型:储存到DB后读取注入

XSS的攻击途径:

  • 节点内容攻击:模版代码<p v-html="from"></p>,攻击载荷http://localhost:8080/?from=%3Cscript%3Ealert(1)%3C/script%3E
  • HTML属性攻击:模版代码<img src="avatar"/>,攻击载荷http://localhost:8080/?avatar=1%22onerror=%22alert(1)%22
  • 富文本:展示富文本内容<p>hello world!</p><script>alert(1)</script>

针对上述攻击方式,如何有效进行防护?

  • 防御节点内容和属性:浏览器自带xss防御X-XSS-Protection,针对于反射型xss
  • 防御节点内容:<>等特殊符号转义为实体字符集
function SaferHTML(templateData) {
    let s = templateData[0];
    for (let i = 1; i < arguments.length; i++) {
      let arg = String(arguments[i]);
  
      // Escape special characters in the substitution.
      s += arg.replace(/&/g, "&amp;")
              .replace(/</g, "&lt;")
              .replace(/>/g, "&gt;")
              .replace(/"/g, "&quot;")
              .replace(/'/g, '&#39;')
              .replace(/ /g, '&#160;');
  
      // Don't escape special characters in the template.
      s += templateData[i];
    }
    return s;
  }
  • 防御富文本:黑名单过滤,过滤掉onerror等属性;白名单保留部分标签和属性,定义[{img: ['src']}]

CSRF--跨站请求伪造

用户登录A网站,在B网站诱导用户发起对A网站的请求(第3步),由于同源策略该攻击请求自动携带了cookie。

跨站请求伪造**利用用户登录态完成业务请求*,可以进行盗取用户资金、冒充用户发帖等行为

针对上述攻击特征,如何进行有效防护?

  • Cookie设置same-site属性,同站点才自动携带cookie
  • 在用户前端页面加入验证信息,如验证码、token<input name="csrf" value="xxx" hidden/>形式,验证请求来源
  • 验证请求的referer地址,禁止来自第三方网站的请求

点击劫持

B网站使用iframe将A网站嵌入,诱导用户点击A网站产生交互。用户不知情,但是亲手操作。

如何防护点击劫持?

  • 使用JStop.location === window.location,禁止内嵌
  • 设置X-FRAME-OPTIONS,禁止内嵌
  • 验证码等其他辅助手段

其他安全

针对HTTP传输窃听等安全问题,使用更安全的协议HTTPS

Cookie常用于保留登录态,如何针保证cookie安全?

  • 设置http-only禁止JS操作cookie
  • 设置same-site避免跨站请求伪造

密码用于证明“你是你”,严禁密码明文存储!

  • 密码泄露渠道

    • 服务器被入侵
    • 通讯被窃听,http窃听
    • 内部人员泄露数据
    • 撞库
  • 哈希算法

    使用复杂密码对抗彩虹表,md5(sha1(md5(id+ab83kd+原始密码+81kdso+盐+1lso;$2))) 变化次数越多,密码越复杂,越安全。

  • 传输的安全性

    • https传输
    • 登录频率限制
    • 前端加密意义有限
  • 生物特征密码

    • 私密性-容易泄露
    • 安全性-碰撞
    • 唯一性,终身唯一,无法修改

还有文件上传安全?

避免上传的文件被当成程序进行执行!

HTTP2

基于RestfulAPi,HTTP/1.1引入“资源”概念,将HTTP从一种面向文档的协议彻底转变为一种面向资源的协议。而HTTP-2的影响,主要在于更快的速度、更安全的传输。

http2如何更快?

分析HTTP请求响应流程图,寻找关键性能指标:

经过分析,得出关键性能指标:

  • 网络指标:延迟、带宽、DNS查询、建立连接时间(TCP三次握手)、TLS协商时间(HTTPS连接)

  • 服务器的优化:首字节时间(TTFB,浏览器从发起请求到接受到第一个字节之间的耗时)、内容下载时间(请求资源随后到达时间TTLB)、开始渲染时间(屏幕什么时候开始显示内容,即用户看到空白页面的时长)、文档加载完成时间(浏览器认为页面加载完毕的时间)

  • 网络的趋势:更多的字节(web内容增长)、更多的资源(引用的资源越来越多)、更高的复杂度(web页面渲染复杂度)、更多的域名、更多的TCP链接

HTTP/1缺陷和优化

缺陷:

  • 队头阻塞:持久连接时,chrome对单个域名开启6个连接,按顺序依次获取资源。如果获取某个资源发生意外,会影响网络传输和web页面渲染。
  • 低效TCP利用:TCP慢启动(拥塞控制),需要多次数据交互才能实现最大体量数据包传输,TCP协议保证了连接正常工作,但是不能保证性能最优。
  • 臃肿的消息首部:资源多请求多,每次都会携带消息首部,消耗资源。
  • 受限制的优先级:HTTP/1主要为请求响应机制,浏览器会先请求优先级较高资源,而优先级低的资源需要等待高优先级请求并处理完成,中间的空档时间浪费了。
  • 可任意选择数据压缩格式,非强制压缩方式
  • 不可控性:第三方资源如果发生问题,会延迟阻塞页面渲染。

优化:

  • DNS查询优化:限制域名数量(合理的拆分域名);dns预解析:<link rel="dns-prefetch" href="//ajax.googlepis.com">
  • 优化TCP连接:preconnect指令:<link rel="preconnect" href="" crossorigin>
  • 避免重定向:重定向可能导致数百毫秒的延迟,请求在云端中重定向
  • 缓存:使用客户端缓存(cache-control控制缓存);CDN缓存。
  • 压缩:代码压缩(空格等);传输压缩gzip等。
  • 避免js阻塞页面:设置async、defeer属性;放在处。
  • 图片优化:图片压缩;响应式图片

HTTP/2反模式

部分针对于HTTP/1的优化,在HTTP/2下可能是反优化:

  • HTTP/2的请求不再是阻塞式的,多请求可以并行处理,就性能而言精灵图失去了意义
  • 不需要进行域名拆分,HTTP/2支持多路复用(HTTP/1为每个域名开启6个请求进程,合理的拆分有利于更多请求能力;但是HTTP/2只开启一个连接,请求多路复用)
  • 图片等不再需要单独设置域名,节省DNS、TCP的连接时间(HTTP/1请求会携带cookie,因此图片等静态资源采用不用的域名避免携带无用cookie;但是在HTTP/2中,首部进行了压缩,同时客户端和服务端会保留“首部历史”,在请求图片时不再每次携带cookie。)

HTTP/2协议介绍

HTTP/2协议在设计时考虑考兼容性,任何不支持HTTP/2的客户端都会简单回退到HTTP/1,一般来说HTTP/2就意味HTTPS,默认开启443端口。

HTTP/2协议大致分为两个部分:分帧层,即h2多路复用能力;数据层,即HTTP数据部分。主要特点:二进制协议、首部压缩、多路复用、加密传输。

  • 连接:初始化一个TCP连接,帧和流在上面传输

  • 帧:请求和响应可以交错甚至多路复用,有利于解决队头阻塞

  • 流:h2链接上独立的、双向的帧序列交换。客户端发起请求,会开启一个流,服务器在这个流上回复。由于有分帧存在,多个请求和响应可以交错,而不会阻塞。

  • 消息:流是用来传输一对请求/响应消息的,h2消息包含HEADERS帧和DATA帧

  • 优先级:h2会分析依赖关系,优先请求最重要的资源

  • 服务端推送:提升单个对象性能的最佳方式,就是在它被用到之前就放到浏览器的缓存里

  • 首部压缩:hpack压缩算法

影响h2性能的要素?

h2的设计目标是提升性能,但是HTTP/2的速度也有命脉:

  • 延迟:h2受影响的增长低于h1
  • 丢包:丢包拥塞导致TCP拥塞窗口波动,h2只开启一个tcp链接,所受影响很大(丢包是h2的命门)。

RestfulApi

RestfulApi内容源自这篇文章:imweb.io/topic/57075…

RestFulApi的主要意义在于将HTTP从面向文档 转为 面向资源

1. 每一个URI代表一种资源
2. 客户端和服务器之间,传递这种资源的某种表现层(客户端想要操作服务器,必须通过某种手段,让服务器发生“状态转化”,这种转化是建立在变现层之上的,即Representational State Transfer---RESTfulApi)
3. 客户端通过四个HTTP动词,对服务器资源进行操作,实现“变现层状态转化”
  • 状态码

    • 使用http状态码(http状态码预定义了错误信息)
    • 自定义,参考微信(0为成功,其余为错误代码):mp.weixin.qq.com/wiki?t=reso…
  • 接口要求

    • 幂等性:对同一个接口,使用同样的条件,一次请求和重复的多次请求对系统资源的影响是一致的。
    • 安全性:如何保证接口的安全性?
  • 实战

    • 版本号参考如下形式:http://api.example.com/v1/zoos
    • 操作方法:GET获取资源、POST新建资源、PUT更新资源(完整)、DELETE删除资源、PATCH更新资源

GraphQL

待学习补充。

缓存

缓存命中流程图:

资源提示与指令

在资源加载方面浏览器提供了些新的方案---资源提示与指令:

  • preload:不同于浏览器预加载,preload可以预加载css和js中定义的资源,并允许决定何时应用每个资源;preload不会阻塞window的onload事件。

    <link rel="preload">

  • prefetch:低优先级的资源提示,允许浏览器在后台(空闲时)获取将来可能用得到的资源,并且将他们存储在浏览器的缓存中。

    • <link rel="prefetch" href="pic.png">
    • <link re="dns-prefetch" href="//baidu.com">
  • prerendering:类似于prefetch,prerendering在后台渲染了整个页面 <link rel="prerender" href="https://www.baidu.com">

  • preconnect:预先浏览器在一个http请求正式发给服务器前预先执行一些操作,包括DNS解析、TLS协商、TCP握手,这消除了往返延迟并为用户节省了时间。<link rel="preconnect" href="//baidu.com" crossorigin>

资源提示与指令

Ajax请求类型

前后端使用ajax进行数据传输,通过Content-type定义数据格式,常用的方式如下:

  1. application/x-www-form-urlencoded

元素标签form的默认编码形式,数据需要转为name=jj&age=17形式传输,推荐第三方库qs进行数据处理。

// application/www-form-urlencode
function ajaxBy1 () {
    let xhr = new XMLHttpRequest()
    xhr.open('POST', 'http://localhost')
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
    xhr.send('name=jj&age=17')
}
  1. application/form-data

元素标签form可以修改enctype=application/form-data,也可以new FormData()新建FormData实例对象,这种方案还支持文件上传。

// multipart/form-data
function ajaxBy2 () {
    const data = new FormData()
    data.append('name', 'jj')
    data.append('age', 18)

    let xhr = new XMLHttpRequest()
    xhr.open('POST', 'http://localhost')
    xhr.send(data)
}
  1. application/json

如果数据结构比较复杂,推荐使用application/json方式,可以直接传输json对象。

// application/json
function ajaxBy3 () {
    const data = {
        "name": "jj",
        "age": 18
    }
    let xhr = new XMLHttpRequest()
    xhr.open('POST', 'http://localhost:5501')
    xhr.setRequestHeader("Content-type","application/json")
    xhr.send(JSON.stringify(data))
}

// 断点续传https://cloud.tencent.com/developer/article/1326932

如果在业务中使用如axios的库进行请求,又该如何实现呢?

推荐

本文大多内容来自下面的资源,推荐阅读。不知道截图是否侵权,如有侵权联系删除。

  1. 图书:《图解HTTP》
  2. Web前后端漏洞分析与防御