HTTP协议学习笔记

364 阅读28分钟

HTTP协议基础及发展历史

Alt 这些深层次的东西有利于以后的工作

Alt

每一个节点都和性能相关,通过优化某些节点,可以达到提高性能的作用

学习http可以给我们带来什么呢?

1,对于前端开发同学,我们能够好的使用http的特性帮助我们进行开发

2,并且也有一些能够提高前端数据和静态资源加载的性能的方案

3,能够提高前后端的一个协作

https和http在创建tcp连接的时候也不同,https有一步是专门保证安全的步骤

HTTP协议要基于tcp/IP协议实现

经典五层网络模型

Alt,

下面我们简单看看底三层,握笔姿势不对 自行忽略哈哈哈 Alt

1

Alt 这几层了解即可。

HTTP协议的发展史

0.9 Alt 1.0 Alt 1.1

大提升,不关闭tcp请求,一个HTTP连接可以有多个tcp请求 Alt

2.0

虽然可以发送多个tcp请求,但是服务端是按顺序接收的,如果前一条迟迟没到,而且下一条tcp很快处理好,那么下一条tcp请求就要等很久才能发送,大大影响效率和性能

 重点: http2解决了这个问题,http2里面http请求在一条tcp连接上是可以并发的

http2最关键的关于前端的优化!推送功能

关于推送功能在前端里面的作用

服务端可以主动发起一些数据传输,那么这样解决了什么问题呢?

我们的web页面都会要求有一些js,css文件,那么他们都是以链接的方式在html的文本信息里面显示着

通过浏览器解析了里面的内容之后,如果再根据链接里面的URL的地址,我们再去请求对应的css和js文件

重点:

那么这里面就会包含一个顺序,我们要先去请求html文本,然后在浏览器里面运行解析了这个文本之后,我们才能去发送css的请求和js的请求

那么有了推送功能之后,我们在请求html文本的同时,可以主动把这个html里面所需要引用的css文件和js文件推送到客户端

这样的话,也就是html 和css js,它们的发送顺序是并行的,而不是串行的,提高了传输性能和效率,明显速度上快多了!

HTTP的三次握手

http请求和tcp连接的关系 Alt

Alt soket,端口,最后一次握手的seq=服务端返回的ack

为什么我们要进行一个三次握手呢? 这是为了防止服务端这边开启一些无用的连接

因为网络传输是有延时的,要通过光纤,还要通过各种中间的代理服务器

比如说,客户端发起了一个创建连接的请求给服务端,服务端接收到了,然后打开端口

但是服务端发回去的数据包丢失了,客户端就一直接收不到这个数据包,然后客户端设置了超时时间,到时间没收到就关闭了

然后又发起了一个新的创建连接请求,但是服务端却什么都不知道,因为如果没有第三次握手,服务端就不知道客户端有没有接收到它返回的信息

并且客户端也没有发送给服务端一个确认,关于它是要创建还是要关闭这个请求

所以,服务端的端口就一直开着,所以这个资源就浪费了。

所以说tcp三次握手主要是为了减小服务器的开销

URI,URL和URN

Alt

Alt

URL 主要是为了识别互联网上一个固定位置,它的资源所在的地方,用这个方式来标志了某个资源之后,我们就可以通过链接的方式去找到这个资源

比如web页面就是通过URL找到HTML文件 返回HTML代码 然后渲染出来的

http://

定义以什么样的协议去访问资源,有很多不同的协议 比如ftp emailto

举个例子,比如下面的是用ftp协议时的展示方式 Alt

后面的是,用户的认证(不过现在不用这个方式了,有更好的认证方式)因为不安全且麻烦

host

原来定义这个资源所在服务器在这个互联网里的位置,host可以是IP,也可以是域名(通过dns解析成IP)

端口

端口,每台服务器有很多端口,在这个服务器上我们可以跑多个web服务,web服务可以监听各种不同的端口

  • 端口就是用来定位某个web服务的

  • host定位物理服务器 端口定位web服务器

默认不带端口的情况下 访问的是80端口, 但是因为端口不方便记忆,所以发布到网上的一般是域名,不是IP方便记忆传播。

/path 路由

定位文件所在的位置

后面的是搜索参数,通过它来传参

hash

代表通过前面的“路径”定位到的文档里面的某个片段,是常用的锚点定位工具

Alt 这个只要了解一下就行

http报文格式

Alt

请求报文

  • 起始行

第一部分:显示method

method有很多种:get获得 post创建 put 更新 delete 删除 等

但是它这个定义只是一张纸上这么写的,我们完全可以按照我们自己的方法去实现这个web服务

比如说你想通过这个method把数据更新掉 完全没有问题 只不过你没有遵循http协议的语义化的定义去做

这样做的坏处是,如果有个不知情的人访问你的服务,他可能一不小心做了他他认为安全的操作,结果数据更新掉了。这就是语义存在的意义

第二部分 显示URL,一般只存放路由部分,因为你发送请求之前,tcp已经连接了,你已经知道你要去哪个主机,所以只需要告诉我你要访问哪个资源就行

第三部分 显示 协议版本 现在一般用http1.1 ,http2很快会普及

  • 头部

描述我想要接收到的数据的格式

没有主体

响应报文

  • 起始行:

第一部分:协议版本

第二部分:code ,代表这个请求现在是处于一个什么样的状态 200表示是正常的 OK的 我可以正常返回给你内容 Alt

200到300 300到400……都有它们的含义,含义是啥,就是后面那个英文的意思,这里是OK

典型的,比如401,表示你发送这个请求的时候没有认证,无法获取资源

但是在国内很多做web开发的同学,做服务器的时候,在他们眼里httpcode只有两种,200和500,不管数据请求是正确的,错的,还是没有认证,都会返回200,再返回一个数据,在这个数据里面,再去说明这个请求到底是正确还是错误。

这样的做法不够优秀,我们要遵从code语义,这样我们的服务更通用,更严谨

首部与主体

它们之间不止一条线,还有个空行

HTTP各种特性总览

node创建本地服务器

创建一个本地服务器并启动

const http = require('http')

http.createServer(function(request,response){
  console.log('request come',request.url)
  response.end('123')

}).listen(8800)

console.log('on')

启动成功

在git bash里面,通过curl,我们可以获得一些信息,其实在浏览器里我们也能看,不过用这个工具更好

CORS跨域

跨域其实是浏览器的规定

我们先来模拟一下跨域,感受一下

01.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    var xhr =new XMLHttpRequest()
    xhr.open('GET','http://127.0.0.1:8801/')
    xhr.send()
  </script>
</body>
</html>

02.js

const http = require('http')

http.createServer(function(request,response){
  console.log('request come',request.url)
  
  response.end('123') 
}).listen(8801)

console.log('on')

01.js

const http = require('http')
const fs =require('fs')

http.createServer(function(request,response){
  console.log('request come',request.url)

  const html =fs.readFileSync('01.html','utf8')
  //设置head
  response.writeHead(200,{
    'Content-Type':'text/html'
    //Content-Type的作用,设置浏览器把文件解析为什么形式
  })
  response.end(html) 

}).listen(8800)

console.log('01.js on')

启动01.js,报错,因为它没有设置服务端允许跨域的头

那我们要怎么设置才能使它可以跨域呢?

我们给02.js添加头部信息,返回头(其实相当于服务端设置允许你跨域访问我)

const http = require('http')

http.createServer(function(request,response){
  console.log('request come',request.url)
  
    response.writeHead(200,{
    'Access-Control-Allow-Origin':'*'
  })
  response.end('123') 
}).listen(8801)

console.log('on')

再次起01服务,没有报错,且在network可以看到请求过来的信息

我们就通过一个步骤就让02服务接受跨域了,但是经过验证,我们发现,即使我们没有给02.js添加头部信息,返回头

启动02服务后,打印了request come/,所以其实这个请求已经发到了,

说明浏览器在发送这个请求的时候,它不知道我们这个服务是不是跨域的,所以它还是会发送请求,然后接收返回内容,只不过浏览器在接收到数据返回的时候,它发现没有头和设置允许('Access-Control-Allow-Origin':'*'

然后它就会把这个返回的数据忽略掉,然后再给你报个错

所以说请求是已经发送了,内容也已经返回了,只不过浏览器在解析这个内容的时候发现有误,所以它帮你拦截掉了!!这就是浏览器的功能

所以如果你在你自己的curl里发送,就没有跨域的概念,任何http请求都可以发送到,也可以返回内容并且输出

jsonp实现的原理

利用了浏览器对link img script等标签里面的url路径,加载内容时,是允许跨域的,浏览器不介意服务器有没有设置头

试一试,我们改一下两个文件

02.js

const http = require('http')

http.createServer(function(request,response){
  console.log('request come',request.url)

  // response.writeHead(200,{
  //   'Access-Control-Allow-Origin':'*'
  // })
  response.end('123') 

}).listen(8801)

console.log('on')

01.html

  <!-- <script>
    var xhr =new XMLHttpRequest()
    xhr.open('GET','http://127.0.0.1:8801/')
    xhr.send()
  </script> -->
  <script src="http://127.0.0.1:8801/"></script>

结果运行发现不报错,也请求成功了

就是在script标签里面去加载了一个链接,这个链接去访问服务器的某个请求,并且返回了内容。因为服务器返回的内容是可控的,所以在返回的内容里面的script标签里面写的可执行的js代码

在代码里面去调用jsonp,在发起请求之前,设置的一些内容

????好抽象

response.writeHead(200,{
   'Access-Control-Allow-Origin':'*'
 })

跨域的头只有这样设置吗?

'*'代表谁都可以访问,所以这样是不安全的,那我们可以怎么改呢?

response.writeHead(200,{
  'Access-Control-Allow-Origin':'http://127.0.0.1:8800'
 })

这样就可以啦,这样就只有http://127.0.0.1:8800/可以访问它

浏览器跨域请求的限制

缓存头Cache-Control的含义和使用

两个容易混淆,no-cache不是不缓存的意思,

no-cache 可以在本地缓存,可以在代理服务器缓存,但是这个缓存要服务器验证才可以使用

no-store 彻底得禁用缓冲,本地和代理服务器都不缓冲,每次都从服务器获取

浏览器调试工具的disable cache功能,相信在座的各位都用过。开启这个功能,浏览器关于当前网站的js、css、图片...等缓存都会失效,所有请求都会重新发送给服务器。ctrl+F5也可以达到同样的效果。

怎么更新浏览器缓存的静态资源

怎么更新浏览器缓存的静态资源呢?(浏览器缓存时间一般设置比较长,一年)

打包完成的js文件名加上一串哈希码(根据它内容进行的哈希计算,所以资源内容变化,文件名变化),文件名变化,请求的url变化,就会发送新的请求啦~

max-age表示多久后缓存过期,单位秒

缓存验证Last-Modified和Etag的使用

Last-Modified

配合If-Modified-Since或者If-Unmodified-Since使用

表示上次修改时间

Last-Modified:服务器发给客户端的响应的头里

Last-Modified被赋给If-Modified-Since

If-Modified-Since:客户端发给服务器的请求的头里

服务端收到If-Modified-Since后对比上次修改时间以验证资源是否需要更新

Etag(更严谨)

配合If-Match或者lf-Non-Match使用

数据签名(对内容进行哈希计算得来的唯一的哈希值)唯一

Etag:服务器发给客户端的响应的头里

Etag被赋给If-Match

If-Match:客户端发给服务器的请求的头里

服务端收到If-Match后对比上次修改时间以验证资源是否需要更新 对比资源的签名判断是否使用缓存

比如这个script文件 ![](https://p9-juejin.b yteimg.com/tos-cn-i-k3u1fbpfcp/f284b395e5bf4b2780626ea10bb210b3~tplv-k3u1fbpfcp-zoom-1.image) 服务端响应 服务端收到的客户端请求 注意

用了no-store之后,关于缓存的信息清除了,所以请求里没有关于缓存(修改时间)的信息

数据库文件里面也可以加字段表示文件上次修改时间

cookie和session

补充token与Cookie

Cookie(复数形态Cookies),又称为“小甜饼”。类型为“小型文本文件”,指某些网站为了辨别用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。

由一个代理服务器下载的页面存储。一个代理服务器为多个用户提供一条通道。缓冲的代理允许一个代理服务器减少对同一个网站的同样页面的请求次数。一旦代理服务器的一个用户请求了某页,代理服务器就保存该页以服务于它的其他用户的同样请求。高流量的网络网关,例如美国在线(AOL)和CompuServe,通过存储流行的站点缓冲来加速网页的显示,例如白宫,就放在一个本地服务器上。一方面这种处理减少了用户等待页面显示的时间,然而由广告支持的站点却由于流量流失而受损,因为缓存不能被捕获或测量。可能降低cookie的作用。

token是用来进行服务端和客户端状态保持的

前端与服务器之间存在跨域用token

不跨域用 cookie或session

跨域是指服务端和客户端在不同的局域网中

cookie

通过在服务端返回内容的head里设置Set-Cookie(可以有多个),发送给浏览器,浏览器会保持cookie, 服务器响应: 浏览器下次同域的请求中会自动带上cookie 键值对,可以设置多个

cookie的属性

max-age和expires设置过期时间

  • 没有设置就是关闭浏览器就没有了

max-age:单位:秒,过了这个时间,respond和request都会没有那个过期的cookie Secure只在https的时候发送

expires:设置的是时间点

HttpOnly无法通过JavaScript的document.cookie这个属性访问cookie,也就是防止通过js访问cookie

  • 安全问题,比如CSRF攻击

在这里普及一下CSRS攻击的原理

CSRS攻击的原理
  • 1、用户M打开浏览器,访问受信任的网站A,输入用户名和密码登录网站A;
  • 2、在用户信息通过验证之后,网站A产生cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
  • 3、用户未退出网站A之前,在同一浏览器打开一个新的tab访问网站B;
  • 4、网站B接受到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点网站A;
  • 5、浏览器接受到这些请求后,根据网站B的请求,在用户不知道情况下携带cookie信息,向网站A发出请求。网站A并不知道该请求是网站B发出的,所以会根据用户M的权限处理该请求,导致来自网站B的恶意代码被执行。

实例:受害者Bob在银行里有一笔存款,通过对银行的网站发送请求http://bank.example/withdraw?account=bob&amount=1000000&for=bob2可以向bob2转账1000000。通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的session,并且该session用户Bob已经成功登陆。 黑客abc在该银行里也有账户,他知道上述的转账的URL,所以abc就可以发送一个请求给银行:http://bank.example/withdraw?account=Bob&amount=1000000&for=abc,但是该请求是来自abc而非Bob,所以他不能通过安全验证,因此该请求不会起作用。 此时,abc想到CSRS攻击方式,他先自己做一个网站,放入代码http://bank.example/withdraw?account=bob&amount=1000000&for=bob2,并且通过广告等诱使B来访问他的网站。当Bob访问该网站时,上面的URL就会发向银行,而且这个请求会附带Bob浏览器的cookie一起发向银行。大多数情况下会失败,因为他要求Bob认证信息,但是如果Bob当时恰巧访问银行服务器不久后,此时的session还没有过期,cookie中含有Bob的认证信息。此时,银行就会执行恶意代码,上述的URL就会得到响应,钱从Bob的账号中转移到了abc的账户,此时Bob毫不知情。等以后Bob再去查日志,也会显示来自于他本人的合法请求转移了资金,没有被任何攻击的痕迹。

怪可怕的

CSRS的预防措施
  • 使用http的referer字段

比如要想访问http://bank.example/withdraw?account=bob&amount=1000000&for=bob就必须先登录http://bank.example,然后通过点击页面上的按钮来转发事件。此时动账请求就会指向以bank.example域名开发的地址,如果黑客使用的是CSRS攻击,他只能在自己网站来实施CSRS攻击,那么他发出的请求中referer就会指向黑客自己的网站,那么服务器就会拒绝访问。服务器只需要在每个动账请求中验证referer,如果指向的是以bank.example域名开发的地址,那么就代表是合法请求,反之,就可能是黑客的CSRS攻击,服务器拒绝该请求。

优点:该方法简单易行,网站的普通开发人员不需要担心CSRS攻击,只需要在最后给所有安全敏感的请求都加一个referer拦截器,不需要改变当前系统的任何代码和逻辑,没有风险,非常便捷。

缺点:该方法也不是万无一失的,因为有些浏览器是可以篡改refere的值,比如IE5和FF12。

  • 在请求地址中添加token并验证

CSRS之所以能够跨站点请求伪造攻击,是因为黑客可以完全伪造用户的请求,该请求中的用户验证信息全部都是存于cookie中,因此黑客可以在不知道这些验证信息的情况下直接利用用户的cookie来通过安全验证。要想抵御黑客的攻击,就要将请求放于黑客不能构造的信息中,并且该信息不存于cookie中,可以在http请求中以参数的形式加入一个随机产生的token中,并在服务器中建立一个拦截器来验证该token,如果请求中没有token或者token的内容不正确,那么就拒绝访问。

token可以在用户登录之后放于session中,然后每次请求都从session中拿出,与请求中的token相比。 如果是GET请求:token会附在地址的后面。 如果是POST请求:在from 的后面加上<input type="hidden" name="csrftoken" value="tokrnvalue"/>

优点:会比refere安全

缺点:在一个网站中,请求的地方有很多,对于每一个请求都要加上token是非常麻烦的,一般会在每次页面加载的时候,使用javascript遍历整个dom树,动态生成的dom需要手动添加。还有就是难以保证token本身的安全。

  • 在http头字段自定义属性添加token属性并验证

将token放于http头中的自定义属性里。 优点:可以一次性给所有类请求都加上http的头属性,并且通过XMLHttpRequest不会被记录到浏览器的地址栏,也不用担心referer被泄露出去。 缺点:Ajax局部刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而前进后退刷新收藏等操作,给用户带来不便。

映射

用chrome工具,hostadmin 将a.test.com这个域名映射到某个IP地址 a.test.com:8888

为了更好呈现,启用nginx

不同域名之间cookie不能共享

domain,代表该域名下的所有二级域名都可以访问该cookie,上级可以访问,比如a.test.com的respond里面不会有,request里面有。 该cookie

同一个主域名下面,二级域名是可以共享一些cookie的

session

使用cookie来保存session,把用户登入的ID或session的一个key设置在cookie里

只要能保证定位到某个用户就代表使用了session

session不一定要写在cookie里面,通过JS写在head里面就行

HTTP长连接

tcp三次握手,建立tcp连接,然后进行HTTP请求, 长连接是指HTTP请求完之后占时不关闭tcp连接

但是实际上,服务器与客户端之间通信一般是高并发,所以tcp一直不关闭可能会影响服务器的负载,但是如果每次都关闭,频繁的重新建立tcp就会有网络延迟上的开销,那么该怎么办呢?

但是实际上,网站的并发量是比较大的

勾选!

表示所有的内容都要重新加载

访问百度首页时,有6个并发的tcp连接,第七个http请求会等待前面的结束,然后复用前面的tcp连接

长连接的标志,respond和request里面, connection:keep-alive

这是一个协商的过程,浏览器发送保持连接的请求,服务器可以拒绝

测试:

<body>
<img src="/test1.jpg" alt="">
<img src="/test2.jpg" alt="">
<img src="/test3.jpg" alt="">
<img src="/test4.jpg" alt="">
<img src="/test5.ipg" alt="">
<img src="/test6.jpg" alt="">
<img src="/test7.jpg" alt="">
</ body>

http.createServer(function (requestresponse) {
	const html = fs.readFilesync('test.html', "utf8')
	const img = fs.readFilesync( 'test.jpg')//把图片读进来
  if (request.url ==='/') {
	response.writeHead(200,{
	'Content-Type': 'text/html'
	})
	response.end(htm1)
 }else {
	response.writeHead(200,{
	'content-Type' : 'image/jpg'
    //'Connection':'close'//把长连接关了,但是我们这个案例注销了
	})
	response.end(img)
   }
}).listen(8888)

先设置低速网络,防止复用 先请求页面,再加载资源,一般第一个资源和请求页面时用的是同一个tcp连接(复用)

第七个http请求会等待前面的结束,然后复用前面的tcp连接

waterfall:某条tcp连接的网络分时

如果长连接关闭, Connection':'close,那么所有tcp连接都不会被复用

  • 但是现在开发我们一般合理运用长连接,我们可以给它设置tcp连接上没有请求时多久关闭tcp连接(keep-alive)。这个是在服务端那边操作的,并不会在http的头上面展示,和http协议没什么关系。

http2

  • 搞了个信道复用,一个用户访问一个网站一个tcp连接就够了,而且整体的速度有一个质的提升。

比如Google就使用的是http2

同域的情况下,所有请求的connection id(一个id对应一个tcp连接)都一样 另一个域下面的,所有ID不一样

虽然http1也可以并发,但是同一个tcp的多个请求还是要按先后顺序的,为了提高性能,用HTTP2

数据协商

请求

  • accept:我想要的数据类型(可以有多种)
  • accept-encoding:数据是怎么样的编码方式(限制服务端数据的压缩方式)

gzip(最流行),deflate,br(压缩比高,未来可能会成为新的主流))

  • accept-language:我想要的语言种类(一般浏览器会根据本机的语言环境设置)
  • user-agent;返回页面应该适应怎样的系统,怎样的浏览器。

语言那的q,表示权重,权重越大指越希望返回什么语言。

返回

  • content-type:从accept里面选一种数据格式作为返回
response.writeHead(200{
" Content-Type":"text/html",
"x-content-Type-options": "nosniff" //告诉浏览器不要猜测我返回的数据类型,防止浏览器按错误格式展示数据
})
  • content-encoding:数据压缩方式

上面的是,数据传输时的大小(包含head,body,首行信息),下面的是body解压之后真实数据的大小(不变)。

返回数据压缩方式设置为gzip之后

response.writeHead( 200,{
"Content-Type": "text/html",
"content-Encoding" : "gzip'
})
response.end(zlib-gzipSync(html))

可以看到更小了

  • content-language:语言种类

演示(post请求)

preserve log:在页面跳转之后把之前的http请求的信息打印出来

<body>
<form action="/form" id="form" method"POST" enctype="multipart/form-data">
 	<input type="text" name=""name">
	<input type="password" name="password">
    <input type="file" name="file">
	<input type="submit">
</form>
</body>

multipart/form-data:表示这个请求是有多个部分的,为什么要用这个?因为有些内容是不能通过字符串进行传输的,比如上传文件是作为二进制作为传输的

后面这串字符串是用来干什么的呢?

是用来分割提交的表单里面的每一项

客户端在request payload里声明数据类型,没有声明的话就是纯文本 ,比如上传文件那一项,我们上传了一张图片,就被声明了鸭~

但是呢注意!当有上传文件这个项时,浏览器就不能显示payload了,所以我们要用ajax的方法来发送fromdata

<script>
var form = document.getElementById("form")//通过id索引到表单
form.addEwentListener("submit", function (e) {//监听submit事件,
	e.preventDefault()
	var formData = new FormData(form)
	fetch( "/form", {
		method:"POST,
		body : formData//像服务端发送表单内容
       })
   })
<script/>

Redirect

if (request.url === '/'){
	response.writeHead(302,{
	  'Location': '/new'
    })
	response.end(")
}
if (request.url === ' /new ' ) {
 response.writeHead(200,{
	'Content-Type ' : 'text/html'
  })
response.end( '<div>this is content</div>')
}

301:永久跳转,比如/永远跳转到/new。(第一次先老后跳新之后,后面直接跳到新的)

就算把301取消为200,刷新还是会跳转到新的URL

除非主动去清理缓存,不然路由会自动跳转到新的URL,因为用的是浏览器缓存的内容。

所以说,用301要谨慎,如果用户不清理缓存就每次都会跳转!

302:临时跳转(每次都会先到老的再到新的地址)

CSP

Content-Security-Policy:内容安全策略

作用:

  • 限制资源获取
  • 报告资源获取越权

限制方式:

  • default-src限制全局,限制所有类型的链接

server.js

const html = fs.readFilesync( 'test.html' , "utf8')
  response.writeHead(200,{
	'Content-Type' : 'text/html',
	'content-Security-Policy' : 'default-src http:https :'
})
response.end(htm1)

在test.html中:

报错,因为我们限制了只能通过http或者https的方式进行加载,也就是不能加载直接写在HTML里的js!

if (request.url === '/') {
  const html = fs.readFilesync( 'test.html', 'utf8')
	response.writeHead(20o,{
  	  'Content-Type ' : 'text/html' ,
      'Content-Security-Policy': 'default-src http: https:'
  })
response.end(html)
}else {
 response.writeHead(20o,{
   'Content-Type':"application/javascript'
  })
  response.end( "console.log("loaded script")')
}

只加载本域名下的外链

允许加载指定域名下的外链

  • 制定资源类型,比如规定这些资源从哪里加载

限制表单链接只能跳转到本域

HTML中写点击跳到百度。

报错

Report-Only用法

response.writeHead(200,{
	'Content-Type' : 'text/html',
	'Content-Security-Policy-Report-Only':report-uri /report'//指定服务器的路径
})
response.end(html)

只做report操作,比如虽然检测到某个资源不能加载,但是不强制它不能加载,发送一个report请求。

浏览器自动发送report请求,帮助我们分析当前网页的安全情况

。。。。这个弃用了!!!

Nginx代理以及面向未来的HTTP

Nginx安装和基础代理配置

server {
  listen       80;//服务在80端口
  server_name  test.com;//通过test.com访问该端口

  location / {
    proxy_pass http://127.0.0.1:8888;//所有的请求都要通过这个代理,我们起了一个node服务
  }
}

代理转发的这个请求的host头被设置为:proxy_pass http://127.0.0.1:8888;

所有host经过代理的层级之后被修改:host中文意思(主机)

在浏览器里面实际发送的request.host是test.com

为什么到服务端这里就变成了:127.0.0.1.8888

因为我们在代理里面设置了,因为浏览器发送的请求是发送给Nginx的,然后通过Nginx转发给服务器,也就是Nginx发起了一个http请求,这个请求发送到实际的node服务,

作为发起方,它认为的host就是它自己设置的目标host:127.0.0.1:8888

  location / {
    proxy_pass http://127.0.0.1:8888;//代理方被要求代理到这个地方
  }

但是我们想拿到浏览器实际发的host怎么办?

proxy_set_header Host $host;

  location / {
    proxy_pass http://127.0.0.1:8888;//代理方被要求代理到这个地方
    proxy_set_header Host $host;//$host是Nginx里的一个变量,每一个请求带过来的真实host变成$host
  }

过程:浏览器-》代理服务器(nginx):127.0.0.1:80-》服务器:127.0.0.1:8888

Nginx里面还有其他变量,不一一说。

nginx的作用

80端口只有一个,如果我们要通过不同的域名访问机器的不同服务,所以需要nginx代理,然后转发到各个服务,这样一台物理机器就可以跑几个不同的服务,节省资源。

怎么从外添加配置?

比如每个项目都有自己的nginx.conf配置文件,比如servers项目,那么我们可以这样导入到nginx的nginx.conf中

Windows下使用的是相对路径,所以把配置文件放在nginx文件夹下的某个文件夹

Mac系统可以随便放在某个文件夹里

include     server/*.conf

Nginx代理配置和代理缓存的用处

代理缓存的作用就是,在不同的浏览器(客户端)访问同一个URL时,只要第一个客户端访问了,之后的客户端访问都会直接用代理服务器里面的缓存,所以更快

'cache-Control':'max-age=2, s-maxage=20, privite,no-store'

缓存过期时间:

从左到右:浏览器缓存专用,代理服务器缓存专用,只允许浏览器缓存,都不能缓存。

可以增加限制,比如请求头的Vary和上一次请求头的Vary得一样,不然就不允许你直接用代理服务器的缓存。

respond: request:

这个有很多应用场景,因为有时URL一样但是数据返回的场景不一样,我们就不能只看URL了

功能提升:

  • 缓存使用内存数据库,因为默认nginx缓存写在磁盘上面,读取效率低。

  • 设置cache-key

HTTPS

http是不安全的

因为它是明文传输的,所以数据包在传输的过程中被黑客截取,会暴露!

比如cookie,get请求的地址,host等等都可以看到,

如果拿到cookie我们可以模仿这个用户的登陆情况,然后去请求用户的数据。

respond里的信息也可以解压被获取

加密

  • 公钥

放在互联网上,所有人都可以拿到的一串加密的字符串,用来加密我们传输的信息

  • 私钥

在服务器中,服务器通过私钥对数据进行解密,中间(互联网中)任何人拿不到私钥。

主要运用在HTTPS的握手的时候

  • 第三个随机数中间人无法知道,所以最后两边生成的主秘钥(是双方同时生成的,是相同的)也是中间人不能破解的。

  • 然后进行加密传输,因为双方都有主秘钥,所以客户端和服务端都可以解密对方!而中间人无法解密

只能拿到一个加密的数据,但是无法解密!

使用Nginx部署HTTPS服务

如何生成私钥和公钥

HTTPS默认使用的端口是443

ssl:HTTPS加密算法

生成一个HTTPS代理服务

为什么不安全,因为Chrome浏览器认可的安全证书是要通过一个权威的机构签发的。

访问http自动跳转到HTTPS功能

第一次 第二次就访问HTTPS了

HTTP2

  • node server还是http1

  • 然后nginx会把HTTP2的请求转化为http1再发送给node server

  • 在nginx里面配置HTTP2更方便,在服务端配更麻烦,所以直接在nginx里配置就行了

在使用https的情况下才可以使用HTTP2

Chrome进入这里可以看HTTP2

pushed=1说明服务器推送了东西,pushed and claimed=0,浏览器出于安全问题,不接收(因为我们服务器的HTTPS证书不安全)

这个网站可以对比http协议各种版本的性能

里面有演示!!!!(加载图片的快慢!)

  • HTTP2主要的性能提升在于,信道复用和分帧传输,而不是在server push

  • 并不是所有浏览器都支持HTTP2,但是nginx可以帮我们做兼容

  • nginx的ALPN方法,

查看test.com网站(服务端)支持什么协议

同时支持http/1.1和http2

加上-k

可以看到默认是使用http2

指定使用http1.1

一般来说,服务端设置成http1.1就行了,因为无论客户端发送的是怎样的,nginx都会帮我们转换成http1.1的请求

完结~