Skip to content

Latest commit

 

History

History
298 lines (187 loc) · 21.4 KB

HTTP.md

File metadata and controls

298 lines (187 loc) · 21.4 KB

HTTP 的方法

  • http1.0 的方法 get post HEAD
  • http1.1 新增五种请求方法 options put delete trace 和 connect

上面的方法的具体作用

  • GET 通常用于服务器请求某些资源
  • HEAD 请求资源的头部信息,并且这些头部和 HTTP GET 方法返回的一样,这个请求方法的一个使用场景是下载一个大文件前先获取这个文件的大小再决定是不是要下载,可以节约带宽资源
  • OPTIONS 用于获取目的资源所支持的通信选项,也叫预请求。用来检测实际发出的请求是不是可以被服务器接受。
  • POST 发送数据给服务器
  • PUT 用户新增资源或者使用请求中的有效负载替换目标资源的表现形式
  • DELETE 用于删除指定的资源
  • PATCH 用于对资源进行部分修改。
  • CONNECT HTTP 1.1 协议中预留给能够将连接改为管道方式的代理服务器
  • TRACE 回显服务器收到的请求,主要用于测试或者诊断

跨域

跨域实现的方案有很多, JSONP ,Nginx 中间人,Windows.name CORS

JSONP

JSONP:这是一种非常古老的跨域手段,利用 HTML 中的 script 标签不受同源策略限制的特性做跨域操作。

  • JSONP 的优点是实现简单,兼容性非常好
  • 缺点是 只支持 get 请求,因为 script 标签只能 get,有安全性的隐患,比如可能会有 xss 攻击

原理:利用 script 发起 get 请求,然后在 callback 函数中获取返回的数据。

Nginx

使用 Nginx 作为跳板机,在服务器端进行转发到别的 IP 服务器上,这样就规避了同源效应。

location /api {
    rewirte ^/b/(.*)$ /$1 break; # 去除本地接口中的 api 前缀,否则会报错 404
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://192.168.0.103:8080; # 转发地址
}

CORS

跨资源共享,使用额外的 HTTP 头信息来告诉浏览器,让运行在一个远端上的 web 被准许访问来自不同源服务器上的指定资源。主要是在 HTTP head 中的以下三个头信息控制

  1. Access-Control-Allow-Origin 后面是跟的跨域服务器网址也可以直接写 * ,那么就是所有的网址都可以
  2. Access-Control-Allow-Methods 后面是跟的允许跨域的方法 GET PUT POST DELETE 等等
  3. Access-Control-Allow-Headers 浏览器支持的所有头部信息字段。

CORS 比 JSONP 强大的地方在于可以支持更多的请求方法,而不是只有一个 GET

CORS 在进行复杂请求的时候,会出现两次请求,基本的比如 post 请求,当设置 content-type: applycation/json 的时候,就会出现两次请求,一次是预请求也就是 options,一次是正常的请求。发生这个的原因是这样的:

cors 跨域

简单请求

不会触发 CORS 预检查,需要满足一些条件,比如说 get,head,post(特殊请求),他们仨的 content-type 要求是 text、multipart/form-data application/x-www-form-urlencoded,还有一些其他的,这里不做记录了。

预检请求

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

window.name

window.name 在不同的页面甚至不同的域名加载以后依旧是存在的,并且可以支持非常长的 name 字符串。

postMessage 函数

在 H5 的 XMLHTTPRequest 里面有个 api 叫 postMessage ,这个方法允许来自不同源的脚本采用异步的方式进行有限的通信。可以实现跨域的消息传递

UDP 和 TCP

TCP 是面向连接,全双工,可靠(重传机制),有序,有拥塞控制机制,传输速度比较慢(相对 UDP),头部大小 20-60 字节

UDP 是无连接,不是全双工,不可靠(丢包以后数据丢失),无序,无拥塞控制,传输速度快,头部大小 8 字节

HTTP 的部首

通用的部首

  • Cache-Control 控制缓存
  • connect 链接管理,逐条首部
  • Transfor-Encoding 报文主体的传输编码格式

请求的首部

  • Accept 客户端或者代理能够处理的媒体类型
  • If-Match 比较实体标记(ETage)在请求方法为 GET 和 HEAD 的情况下,服务器仅在请求的资源满足此首部列出的 ETag 值时才会返回资源。而对于 PUT 或其他非安全方法来说,只有在满足条件的情况下才可以将资源上传。ETag 之间的比较使用的是强比较算法,即只有在每一个字节都相同的情况下,才可以认为两个文件是相同的。 mdn if-match 和协商缓存有关系
  • If-None-Match 对于 GET 和 HEAD 方法来说,当且仅当服务器上没有任何资源的 Etag 属性值于这个首部中列出的相匹配的时候,服务器端才会返回所请求的资源。和 if-match 相反
  • If-Modify-Since 在请求头消息中,有这个头部消息的是条件式的请求,只有当资源在指定的时间之后没有进行过修改的情况下,服务器才会返回请求的资源。如果资源发生了修改,那么就会返回 412 错误
  • Range 实体的字节范围请求
  • Authorization 用户认证信息
  • Host 请求资源所在的服务器
  • User-Agent 客户端程序信息,操作系统啊,软件版本啊,开发商啊之类的

响应的首部信息

从服务器端向客户端发起响应的时候,使用的字段

  • Location 使得客户端重定向的 URI
  • ETag 能够表示资源唯一资源的字符串
  • Server 服务器的信息

实体首部字段

针对请求报文和响应报文的实体部分使用首部

  • Allow 资源可支持的 HTTP 请求的方法 Allow: GET, POST, HEAD ,一般和状态码 405 有关系
  • Last-Modified 资源最后被修改时间
  • Expires 实体资源文件的过期时间,和协商缓存有关系。

状态码

100 - 199

表示信息正在被响应,用的比较少。

2xx

  • 200 表示请求正在被正确的处理
  • 206 进行范围请求

3xx

  • 301 永久性重定向,表示已经分配了新的 URL
  • 302 临时性重定向,表示资源临时分配了新的 URL
  • 303 http1.1 中将 302 拆出来,303 表示临时重定向,表示客户端应该使用 get 方法请求,会把 post 方法转成 get
  • 304 服务器允许访问资源,但是有缓存可以使用
  • 307 临时重定向,和 302 类似
  • 308 永久重定向,和 301 的区别是 308 的请求方法和消息主体不会发生变化,而 301 有可能会变成 get 方法。

4xx

  • 400 请求语义错误,或者参数错误
  • 401 没有权限,用户验证错误
  • 405 Method 不被允许
  • 403 请求被拒绝

5xx

  • 500 在服务器执行的时候发生了错误

302 307 303

302 是 http1.0 的状态码,在 http1.1 中为了细分临时重定向,划分出来 303,307 303:表示客户端应该使用 get 方法请求,它会把 post 转成 get 方法。 307: 307 不会把 get 方法转成 post 会按照客户端发起的请求去请求资源

HTTP 和 HTTPS

http 是明文传输的,所有的信息都可以被第三方抓包看清楚,对于一些敏感信息是不安全的,所以 HTTPS 就是为了解决这个问题出现的。

HTTPS 安全性

HTTPS 的加密方案是将对称加密和非对称加密结合起来。

对称加密:双方公用一个秘钥,性能好,简单,但是秘钥容易被黑客破获

非对称加密: 优点是加密方案不会被破解,缺点是很慢,性能并不好

  1. 公钥 + 私钥 = 秘钥对
  2. 私钥加密的数据,只能对应的公钥打开,也就是一把钥匙开一把锁。。
  3. 通信客户端和服务器都有自己的公钥,在通信之前,要把彼此的公钥发送给对方。
  4. 然后通信双方用对方的公钥加密数据,然后把加密好的数据发给对方,对方再用自己本地的私钥解密数据

那么结合对称加密和非对称加密,将对称加密的秘钥使用非对称加密的公钥进行加密,然后发送出去,接收方用本地的私钥解密,这样就得到加密的秘钥,然后再用对称加密进行传输数据

中间人问题

上面的逻辑看着没问题,但是如果在通信双方的中间有个中间人,把原本双方需要互换的公钥全部换成自己的公钥,那么这时候就会出现中间人可以用自己的私钥轻松解密所有的数据。为了解决这个中间人信任问题就产生了 CA 证书,用来证明非第三方。

为了进一步防止 CA 证书被篡改引发安全问题,引入了数字签名,也叫做指纹。证书发布者根据指纹算法,一个 hash 算法,计算出整个证书的指纹 hash 值。然后使用者在使用的时候,也用 hash 算法计算一下指纹,如果这两个指纹对的上,就说明没有被篡改。

HTTP2

在 http1.x 时代,我们在发起请求的时候,因为浏览器的限制,一次最多是可以处理 6-8 个请求,当请求被阻塞的时候,后面的请求就只能一直排队,在某些网络不好或者一下子有很多并发的请求的时候,就会出现请求阻塞的问题

在开启了 H2 以后请求就会在一个管道里并发处理,请求不会依赖前面的请求结束,而且可以并发响应。 这是因为 H2 对于同一个域名下的请求是基于流的,理论上是所有的请求都可以基于一个 HTTP 链接进行请求,实际上也是这么做的。所以这一个请求链接就可以完成页面加载和后期数据请求,不用担心数据流错乱。

H2 并不是把 tcp 传输层改成了并行链接,TCP 传输层的阻塞是没有解决的。TCP 依旧是一个独木桥,仅仅是在应用层 HTTP 协议上进行了优化,但也正是这些重要的优化使 HTTP2.0 成为了全双工的协议,单连接多资源的方式克服了 TCP 慢启动带来的负面影响,更加有效地利用了 TCP 连接,使连接性能得到了极大的提升。也充分地利用了 TCP 协议的带宽来降低 HTTP 延迟,并且减少了连接的内存占用,单个连接的吞吐量增大,网略阻塞和丢包的恢复速度增快等

三次握手

TCP 协议是面向连接的,稳定的有重传机制的,有序的,全双工,有拥塞控制机制,相对 UDP 较慢,头部信息 20-60 字节,所以在建立连接的时候,需要有三次握手,用来确定连接建立稳定有序,拆除连接的时候,就需要四次挥手,用来保证数据的稳定传输。

三次握手

所谓的三次握手,就是指的建立一个 TCP 连接的时候,服务端和客户端需要发送三个包,才可以建立一个稳定的连接。三次握手的目的是连接服务器指定的端口,建立 TCP 连接,并同步连接双方的序列号,和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect() 的时候,就会触发三次握手,这个过程的示意图如下。

三次握手过程示意图

  • 第一次握手(SYN=1 seq = x):

    客户端发送一个 TCP 的 SYN 标志位置 1 的包,指明客户端打算链接的服务器的端口,以及初始序号 X,保存在包头的序列号 Sequence Number 字段里。发送完毕以后客户端进入 SYN_SEND 状态

  • 第二次握手 SYN=1 ACK= 1 seq=y ACKnum = x + 1,服务器发送确认包(ack)应答,也就是 SYN 和 ACK 标志位都是 1,服务器端选择自己的 ISN 序列号,放到 Seq 域里,同时将确认号 number 设置为客户端的 ISN +1 也就是 X+1。发送完毕后服务器进入 SYN_RCVD 状态。

  • 第三次握手 ACK = 1 ,ACKnum = y + 1 客户端再次发送确认包,SYN 标志位是 0 ,ACK 标志位是 1,并且把服务器发来的 ACK 序号段加一,放在确定字段中发送给对方,发送完毕后客户端进入 ESTABLISHED 阶段,当服务器端接收到这个包的时候,也进入 ESTABLISTED 状态,TCP 结束。

四次挥手

TCP 的拆除需要发送四个包,客户端和服务器端任意一方都可以发起挥手动作。

  • 第一次挥手, FIN = 1.seq = x 假设客户端要中断链接,客户端发送一个 FIN 标志位 1 的包,表示自己没有数据可发送了,但是任然可以接接收数据,发送完毕以后进入 FIN_WAIT_1 状态。
  • 第二次挥手 ACK = 1 ACKnum = x + 1 服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接到客户端关闭连接的请求,但是还没准备好关闭连接。发送完毕后服务器进入 CLOSE_WAIT 的状态,客户端接收到这个包以后进入 FIN_WAIT2 状态。等待服务器关闭连接
  • 第三次挥手 FIN = 1,seq = y 服务器端准备好关闭连接的时候,向客户端发送 FIN = 1 的包,发送完以后服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个 ACK。
  • 第四次挥手 ACK = 1 ,ACKnum = y + 1. 客户端接收到来自服务器端的关闭请求,发送一个 确认包,并进入 TIME_WAIT 阶段,等待可能要出现重传的 ACK 包,服务器在接收到这个确认包以后,关闭连接,进入 CLOSE 状态,客户端在等待了 2MSL 两个最大段生命周期之后,没有手段服务器端的 ACK,这时候就是认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSE 的状态。

四次挥手

SYN 攻击

在三次握手的过程中,服务器在发送了 SYN_ACK 以后,收到客户端的 ACK 之前的 TCP 连接称之为半连接 SYN 攻击指的是在短时间内伪造大量不存在的 ip,向服务器不停的发送 SYN 包,服务器回复确认包,等待客户端的回应,因为 ip 源地址是伪造的,因此服务器一直得不到回应,这时候服务器就需要一直重发,直到超时,这些伪造的 SYN 包就会一直占用连接通道,正常的 SYN 包就会被抛弃,导致服务器网络拥塞或者系统瘫痪。

一般在服务器上出现大量的半连接,且 ip 是无序的时候,就可以认为是有人发起了 SYN 攻击。防御 SYN 攻击就需要缩短 SYN 超时时间,增加最半连接数,过滤网关防护。

对于前端而言,缓存是改善前端性能,提升用户体验等的一个很重要的手段,适当的缓存可以极大的缓解服务器的压力。

永久重定向

重定向是永久的,表示的是原有的 URL 不能再被使用,而应该选择用新的 URL。

编码 含义 处理方法 应用场景
301 Moved Permanently get 方法不会变更,其他方法可能会变更成 get 方法 网站重构
308 Permanently Redirect 方法和消息主体都不发生变化 网站重构,用于非 get 方法

临时重定向

304

http 304 未改变说明无需再次传输请求的内容,也就是可以使用缓存的内容,这通常是在一些安全的方法或者

HTTP 缓存

缓存有很多种,但是对于前端来说 HTTP 缓存无疑是非常重要的一种,是需要优先掌握的

HTTP 缓存分为强缓存和协商缓存,优先级较高的是强缓存,在命中强缓存失败的时候,才会走协商缓存。

强缓存

强缓存是利用 http 头中的 Expires 和 Cache-control 两个字段进行控制的。当请求再次发出的时候,浏览器会根据其中的 expires 和 cache-control 去判断是不是命中了强缓存,如果是命中了,就不再和浏览器发生交互。直接去缓存中获取资源。

在强缓存中有两个关键字,分别是 expires 和 cache-control 。

expires:后面是一个 date 时间日期。表示资源的到期日期,但是这个东西有个问题就是本地的时间可能和服务器不一样,或者可以把本地的时间手动改掉,这样的话就不是我们想要的准确的对比结果了。有一定的局限性。

Cache-control:35000 number 类型,代表的是多少秒。这样的话就可以和服务器很准确的去交互,判断资源是不是过期了。

但是在 cache-control 里不仅仅有 max-age,还有 s-maxage,s-maxage 的优先级高于 max-age

cache-control: max-age=3600, s-maxage=31536000 public private no-cache, no-store,

s-maxage 表示 cache 在代理服务器上的缓存有效时间,且只对 public 缓存生效,对于比较大的架构,一定存在 CDN 这样的静态资源服务器,那么就存在服务器的资源缓存有效时间,那么 s-maxage 就是给这个准备的。这时候会出现 public 和 private 的概念,public 可以被代理服务器缓存也可以被浏览器缓存,但是 private 就只可以被浏览器缓存。

no-cache : 设置了 no-cache 的时候,就会在每次发起请求前,绕开浏览器直接去服务器确认该资源是不是过期,走的是协商缓存的路线。 no-store : 设置了 no-store 的时候,就会是每次请求不使用任何的缓存策略,直接去服务器请求完整的资源。 no-store 的优先级最高。

协商缓存

协商缓存是浏览器和服务器之间协作下的缓存机制,协商缓存机制依赖浏览器和服务器之间的通信,在协商缓存机制下,浏览器会向服务器询问缓存的信息,进而判断是不是要发起请求或者是去本地获取缓存信息。在协商缓存中有两个比较重要的点就是 Last-modify 和 E-tag

Last-modify :通过服务器上文件修改的时间戳和当前请求的时候 HTTP 头信息中携带的 Last-modify 做对比,看是不是一致,如果两者的时间是不一致的,那么就会发起请求。但是这个 Last-modify 有个问题就是他不是很准确,存在这样的情况,当我们修改了文件,但是没有修改文件的内容,这时候,服务器上的文件时间会发生变化,Last-modify 和服务器上的时间不一致,会发起请求,这不是我们想要的,再有就是 Last-modify 时间是秒为单位的,如果在 100ms 内修改了文件,请求的时候,Last-modify 和服务器上的时间是一样的,这时候会拿不到最新的文件。这是弊端 E-tag:E-tag 的出现是为了解决上面提及的那两个弊端,当文件修改了以后,E-tag 就会发生变化,这时候就会触发一次完整的请求。E-tag 虽然好,但是它会消耗服务器的性能,所以 last-modify 和 E-tag 是要根据业务去判断应该用那个。

CDN

一般大型的 web 架构静态资源走 CDN 是一个规定,CDN 的核心功能点有两个,一个是回源,一个是缓存

回源:CDN 服务器发现自己这里没有客户端请求的这个静态资源,就会去找根节点请求这个资源。 缓存:将回源得到的静态资源存放在自己服务器上。

利用 CDN 有很多好处,节省服务器资源,加快静态资源下发给客户端,增强客户体验,让客户可以更快的拿到资源。性能优化等 CDN 也会发生 CDN 劫持,可能会出现我们的静态文件内容被替换,发生一些不被我们期望的事情。可以通过 SRI 也就是 subresource integrity 判断。我们在 script 标签里添加 integrity 属性,这个属性是有两个设置的地方,一个是加密方式,用中划线隔开,另一个是加密后的 hash。我们就可以通过 hash 是不是相同来判断是不是发生了 CDN 劫持。

前端安全:

  1. iframe ,我们现在的这个项目是一个部署在内网的项目,因此在项目里就直接使用了 sandbox 是空 也就是直接禁止了所有的 iframe 行为。sandbox 里面有很多设置,可以控制 iframe 访问父级 dom cookie 跳转,执行脚本 执行表单 打开新网页等行为。
  2. opener 在我们打开一个新的窗口的时候,一个是 html a link 标签使用 href 打开新的网页,另一个是 window.open 打开新的网页,攻击者在攻击的时候,会通关 opener 里面的数据,篡改前一个页面的地址,让你找不到上一个页面。在 a link 等标签里使用 rel='noopener norefere nofollow' 但是老旧浏览器不兼容。

线程和进程的区别

进程是资源分配的最小单位,线程是 CPU 调度的最小单位。 可以做这样的一个比喻:进程是火车,线程是车厢

  • 线程在进程下行进(单车厢是没办法走的)
  • 一个进程可以有多个线程(一列火车可以有很多的车厢)
  • 进程之间数据交换比较麻烦 (不同的火车之间人员流动就很麻烦,只能在站台做交换)
  • 同一个进程下的不同线程数据交换比较方便。(同一列火车中不同的车厢人员流动就很容易。)
  • 进程比线程消耗更多的计算机资源(运送一批货品,多个火车比一列火车多个车厢会更加消耗资源)
  • 进程之间不会相互影响,一个线程挂掉,会影响整个进程。(两列火车,一列起火不会影响另一列。但是一列火车的车厢起火会影响整列火车)
  • 进程使用的内存可以上锁,当进程中的某个线程在使用内存的时候,其他的就要等它使用完。(就像火车上的洗手间)互斥锁
  • 进程使用的内存地址可以限定使用量,(比如火车上的餐厅,只能是多少人使用,一旦超过,那么就要在外面等候。)信号量