http详解 一, http请求过程: 二, 网络协议分层: 三, http历史: 四, 跨域CORS 五, HTTP请求头以及缓存Cache-Control 六 https:

1,http使用场景:

网页输入url
ajax获取数据
img标签加载图片

2,主要技术点:缓存,这是最能优化性能的地方!!!

cache-control:
public,private
must-revalidate
no-chche,no-store

3,有意义的头

Content-Type,Content-Encoding等用来约束数据类型
Cookie保持会话信息
CORS跨域且保证安全性限制,不让非法人员使用

4,TCP连接问题:

三次握手
https链接创建过程,为什么安全
什么是长链接,为什么需要长链接
http2信道复用为什么可以提高性能

一, http请求过程:


这些节点对web开发人员是透明的,但是深入理解可以帮助开发人员优化性能!
(浏览器调试工具performance会记录每个节点的时间点、时间消耗)
流程:
1,startTime之后就要开始跳转(redirectStart),因为浏览器要判断地址是否已经永久跳转至新地址
2,看缓存(cache)
3,DNS解析
4,创建tcp链接(三次握手),如果请求是https,就要创建https链接,在http基础上加一个保证数据安全的过程
5,发送数据包
6,返回数据

二, 网络协议分层:


物理层:

定义物理设备如何传输数据(硬件,网卡,网线)

数据链路层:

在通信的实体间建立数据链路连接(0101之类)

网络层:

为数据在节点之间传输创建逻辑链路(寻找百度的服务器)

传输层:

向用户提供可靠的端到端(End-to-End)服务(从自己电脑到百度链接之后,两端如何传输数据,传输的方式都在这里定义。传输大数据分包,分片,数据过去之后数据组装)。传输层向高层屏蔽了下层数据通信的细节,http这一层不需要关心。

应用层:

为应用软件提供了很多服务;构建与tcp/ip协议之上;屏蔽了网络传输相关细节

三, http历史:

http/1.0:

1,增加了很多命令,POST,PUT。。。
2,增加了status code,header
3,多字符集支持、多部分发送、权限、缓存

http/1.1:

1,持久连接:http1里面一个http请求发送就要在客户端和服务端之间创建一个http连接,传输之后就关闭了,过程中有tcp三次握手,消耗性能
2,pipeline:同一个连接里面可以发送多个请求,服务端发送回来的数据需要等待顺序返回,串行。http2进行了优化,变成并行
3,增加了host和其他命令:host可以在同一台服务器上跑多个web服务,node和java,host判断提供哪个服务

http/2:

1,所有数据二进制传输
2,因为第一点,所有pipeline可以并行操作,传输效率质的提升
3,头信息压缩以及推送等提高效率的内容,解决http1.1效率低下的问题
http1.1每次发送都要完整的头信息,如content-type信息都是字符串, 消耗性能,压缩之后能节约性能
推送:http请求只能客户端先发请求,服务器接收请求;http2服务器端可以主动发送请求。比如html页面,先获取html信息,才能发送请求获取css和js数据,现在http2可以主动发送数据,变串行为并行

https:

安全版本的http1

3.1 HTTP报文

请求报文:

  • method:GET,POST(用来定义对资源的操作,GET,POST,PUT,DELETE)
  • url:具体请求资源的地方
  • 协议:http1.1和http2为主

响应报文:

  1. 协议 状态 状态代表的具体含义
  2. 首部跟主体空行隔开
  3. HTTP CODE:定义服务器对请求的处理结果
    (1) 100-199:操作要持续进行,后续才返回数据
    (2) 200-299:操作成功
    (3) 300-399:操作需要重定向,用别的方式获取数据
    (4) 400-499:操作失败;401:没有权限
    (5) 500-599:操作存在错误
    \color{red} {好的http服务是可以通过HTTP CODE来判断结果}

3.2 URI,URL,URN

  • uri:Uniform Resource Identifier/统一资源标志符,名词的定义为了识别互联网上固定位置的资源,包含url和urn
  • url:UniForm Rsource Locator/统一资源定位符
    比如:http://user:[email protected]:80/path?query=string#hash
    默认带80端口
    /是当前文件夹根目录,现在/path的使用是在代码中执行
    hash:查看文档某个片段,作为锚点
    此种格式就是url(http,ftp使用)
  • urn:永久统一资源定位符
    内容换地址,通过urn也能访问到,因为404之后url上不知道新的地址;目前没有成熟的方案

3.3 HTTP三次握手

  • http没有连接的概念,只有请求和响应,请求和响应都是数据包,之间要经过传输通道,就在tcp里面创建的客户端发起,服务端接收的连接,http请求是在这个连接上发送的。
  • http1中,在一个http请求时创建tcp连接,请求发送之后,服务器响应,http就断开了
  • http1.1中,可以声明http连接可以保持连接,
  • http2中,http请求可以并发,一个用户对一个网页只需要一个tcp连接

之所以需要三次握手,因为网络连接有消耗,数据传输有延时,数据可能丢失,客户端如果没有接收到服务端接收的信息,超时之后会发送新的连接,这样旧的连接就不会断开,十分浪费
windows网络抓包工具:wiresshark

3.4 HTTP客户端

在命令行中请求网页数据,处处有惊喜哦:
1,curl baidu.com
2,curl www.baidu.com
3,curl -v www.baidu.com

四, 跨域CORS

实现一个简单的跨域访问:

node后端配置跨域
response.writeHead(200,{
    'Access-Control-Allow-Origin':'*'   //表示所有的域都可以访问
    'Access-Control-Allow-Headers':'X-Test-Cors', //fetch预请求
    'Access-Control-Allow-Methods':'POST,PUT,Delete', //除了默认get之外预请求的类型
    'Access-Control-Max-Age':'1000', //单位是s
})
html:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div>这是一个test页面</div>
  <script>
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'http://127.0.0.1:8887/')
    xhr.send()
    console.log(11)
  </script>
</body>
</html>

server:前端服务代码
const http = require('http')
const fs = require('fs')
http.createServer(function (request, response) {
  console.log('request come', request.url)
  const html = fs.readFileSync('test.html', 'utf8')
  response.writeHead(200, {
    'Content-Type': 'text/html'
  })
  response.end(html)
}).listen(8888)
console.log('server listening on 8888')

server2:后端服务代码
const http = require('http')
http.createServer(function (request, response) {
  console.log('request come', request.url)
  response.writeHead(200, {
    'Access-Control-Allow-Origin': 'http://127.0.0.1:8888',   // 设置可以跨域的服务器,*代表全都可以
    'Access-Control-Allow-Headers': 'X-Test-Cors',
    'Access-Control-Allow-Methods': 'POST, PUT, DELETE',
    'Access-Control-Max-Age': '1000'
  })
  response.end('123')
}).listen(8887)
console.log('server listening on 8887')

\color{red}{注意:并不是设置了Access-Control-Allow-Origin就一定可以跨域:}

html:
    fetch('http://127.0.0.1:8887', {
      method: 'POST',
      headers: {
        'X-Test-Cors': '123'    // 会先向后台发一次预请求,通过之后再发正式请求
      }
    })
    
server2:
    'Access-Control-Allow-Headers': 'X-Test-Cors',   //不配合设置就无法跨域
    'Access-Control-Allow-Methods': 'POST, PUT, DELETE', // 这里也要和html里面的method对应
    'Access-Control-Max-Age': '1000'  // 这个请求最长的连接时间,在这个时间段内不需要发送预请求

需要注意的几点:

  1. CORS预请求(OPTIONS方法),method默认允许的方法:GET,POST,HEAD
  2. 默认允许的数据类型Content-Type:
    text/plain
    multipart/form-data
    application/x-www-form-urlencoded
  3. 其他请求头限制。。。

五, HTTP请求头以及缓存Cache-Control

重点来了!



public:http请求返回的请求经过的任何路径(包括代理服务器,浏览器)都可以进行缓存
private:只有浏览器可以缓存
no-cache:都不能缓存

5.1 Cache-Control缓存时间:

max-age<seconds>:缓存时间
s-maxage<sceonds>:代替max-age,但是只有在代理服务器才会生效
max-stale<sceonds>:发起请求方主动携带(不是浏览器,应该是代码里写的),max-age过期之后,如果max-stale可以代替max-age

尝试下代码:

html:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div>这是一个test页面</div>
  <script src="/script.js"></script>
</body>
</html>

server.js:
const http = require('http')
const fs = require('fs')

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

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8')
    response.writeHead(200, {
      'Content-Type': 'text/html'
    })
    response.end(html)
  }

  if (request.url === '/script.js') {
    response.writeHead(200, {
      'Content-Type': 'text/javascript',
      'Cache-Control': 'max-age=20'        //设置后,在缓存期内,客户端会直接在本地缓存中读取数据,即使后台修改
    })
    response.end('console.log("script loaded")')
  }
}).listen(8888)

console.log('server listening on 8888')

5.2 Cache-Control重新验证:

  • must-revalidate:max-age过期之后,要到服务器端验证是否真的过期,而不能直接使用本地缓存
  • proxy-revalidate:用在缓存服务器的must-revalidate

5.3 Cache-Control其他操作:

  • no-store:和no-cache区分,no-cache是指可以在浏览器和代理服务器缓存,但是要去服务器验证,服务器说可以才可以使用;no-store是彻底的都不能存储缓存
  • no-transform:proxy服务器使用。不允许代理服务器对返回的内容进行压缩等改动
    注意:这些头都只是约定,并不是强约束

5.4 Cache-Control资源验证

  • etag等
server.js
const http = require('http')
const fs = require('fs')

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

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8')
    response.writeHead(200, {
      'Content-Type': 'text/html'
    })
    response.end(html)
  }

  if (request.url === '/script.js') {

    const etag = request.headers['if-none-match']
    if (etag === '777') {
        // 304表示资源未修改,浏览器会直接拿第一次访问获得的数据
      response.writeHead(304, {    
        'Content-Type': 'text/javascript',
        'Cache-Control': 'max-age=2000000, no-cache',
        'Last-Modified': '123',
        'Etag': '777'
      })
      response.end('mingming')
    }
    else {
        //第一次访问时
      response.writeHead(200, {
        'Content-Type': 'text/javascript',
        'Cache-Control': 'max-age=2000000, no-cache',
        'Last-Modified': '123',
        'Etag': '777'
      })
      response.end('console.log("script loaded twice")')
    }
  }
}).listen(8888)

console.log('server listening on 8888')

5.5 Cookie和Session

Cookie

  • 服务端返回数据的时候通过Set-cookie的header保存在浏览器里面的内容,浏览器保存之后下次同域请求会带上cookie,用来识别用户
  • max-age(多长时间)和expires(到哪个时间点)来设置过期时间
  • Secure只在https才会发送,http没有
  • HttpOnly:无法通过document.cookie访问,用来避免攻击,如CSRS攻击,通过网页注入脚本拿到用户cookie到服务器拿到用户数据
  • Set-cookie可以写多个,有时效限制,不设置过期时间,浏览器关闭之后就没有了
const http = require('http')
const fs = require('fs')

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

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8')
    response.writeHead(200, {
      'Content-Type': 'text/html',
      'Set-Cookie': 'id=123'    //在这里直接给客户端设置cookie
      'Set-Cookie': ['id=123', 'name=ming']  //设置多个cookie
      'Set-Cookie': ['id=123;max-age=4', 'name=333'] //设置时间
      'Set-Cookie': ['id=123; max-age=2', 'abc=456;domain=test.com'] 
      //同一个域名下,给其他地址设置cookie,使用demain
      //记住,不能给自己的上级域名设置,会跨域
    })
    response.end(html)
  }

}).listen(8888)
console.log('server listening on 8888')

5.6 domain

不同域的cookie不能共享,只能单独设置,也可以通过设置domain完成二级域名恭共享cookie
演示代码:代码溜了

5.7 数据协商

请求:

  • Accept:指定需要的数据类型
  • Accept-Encoding:限制服务端数据压缩类型,gzip(最流行),deflate,br(最少 ,以后可能主流);服务端将数据进行压缩,在客户端进行解压,一般超过1kb的时候,传输的size会小于解压之后的size
  • Accept-Language:指定返回数据类型
    User-Agent:浏览器相关信息(指定移动端,PC端)
user-agent: 
Mozilla/5.0                                // 老的浏览器默认的头;
(Macintosh; Intel Mac OS X 10_15_5)        // 电脑系统 
AppleWebKit/537.36 (KHTML, like Gecko)     // 浏览器内核,KHTML渲染引擎,类似于Gecko(火狐浏览器引擎)
Chrome/83.0.4103.106 Safari/537.36         // 浏览器

返回:

Content-Type:返回的数据格式

content-type: text/html; charset=utf-8  ||    text/javascript 。。。

Content-Encoding:对应Accept-Encoding
Content-Language:对应Accept-Language

5.8 Redirect

  • 302是临时跳转
  • 301永久跳转,意味着下次进入的时候url1会直接在浏览器更换url2,url1被缓存在浏览器中,disk cache,缓存时间很长,除非清缓存,服务器无法主导,所以这个使用301要非常谨慎
const http = require('http')

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

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

console.log('server listening on 8888')

5.9 Content-Security-Policy,内容安全策略

作用:

  1. 限制资源获取:资源从哪里获取,请求发到哪里
  2. 报告资源获取越权:获取不应该获取的资源时,给服务进行报告,做出调整
    default-src限制全局
    特定资源类型,限制资源范围:connect-src,img-src,script-src。。。
const http = require('http')
const fs = require('fs')

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

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8')
    response.writeHead(200, {
      'Content-Type': 'text/html',
      // 'Content-Security-Policy': 'script-src \'self\'; form-action \'self\'; report-uri /report'
    })
    response.end(html)
  } else {
    response.writeHead(200, {
      'Content-Type': 'application/javascript'
    })
    response.end('console.log("loaded script")')
  }
}).listen(8888)

console.log('server listening on 8888')

html:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta http-equiv="Content-Security-Policy" content="script-src 'self'; form-action 'self';">
  <title>Document</title>
</head>
<body>
  <div>This is content</div>
  <script>
    console.log('inline js')
  </script>
  <script src="test.js"></script>
  <script src="https://cdn.bootcss.com/jquery/3.3.1/core.js"></script>
</body>
</html>

六 https:

参考资源:https://coding.imooc.com/class/225.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章