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为主
响应报文:
- 协议 状态 状态代表的具体含义
- 首部跟主体空行隔开
- HTTP CODE:定义服务器对请求的处理结果
(1) 100-199:操作要持续进行,后续才返回数据
(2) 200-299:操作成功
(3) 300-399:操作需要重定向,用别的方式获取数据
(4) 400-499:操作失败;401:没有权限
(5) 500-599:操作存在错误
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:
Document
这是一个test页面
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')
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' // 这个请求最长的连接时间,在这个时间段内不需要发送预请求
需要注意的几点:
- CORS预请求(OPTIONS方法),method默认允许的方法:GET,POST,HEAD
- 默认允许的数据类型Content-Type:
text/plain
multipart/form-data
application/x-www-form-urlencoded - 其他请求头限制。。。
五, HTTP请求头以及缓存Cache-Control
重点来了!
public:http请求返回的请求经过的任何路径(包括代理服务器,浏览器)都可以进行缓存
private:只有浏览器可以缓存
no-cache:都不能缓存
5.1 Cache-Control缓存时间:
max-age
s-maxage
max-stale
尝试下代码:
html:
Document
这是一个test页面
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('this is content')
}
}).listen(8888)
console.log('server listening on 8888')
5.9 Content-Security-Policy,内容安全策略
作用:
- 限制资源获取:资源从哪里获取,请求发到哪里
- 报告资源获取越权:获取不应该获取的资源时,给服务进行报告,做出调整
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:
Document
This is content
六 https:
参考资源:https://coding.imooc.com/class/225.html