五层模型
浏览器从输入url到http请求返回的过程
http发展历史
http/0.9:
1.只有get命令
2.没有HEADER等描述数据的信息
3.服务器发送完毕,就关闭tcp链接
http/1.0:
1.增加了很多命令,如:post
2.增加status code 和header
3.多字符集支持,多部分发送,权限,缓存等
http/1.1:
1.持久链接
2.pipline
3.增加host和其他一些命令
http/2.0
1.所有数据以二进制传输
2.头信息压缩以及推送等提高效率的功能
3.同一个链接里吗发送多个请求不再需要按照顺序
跨域
// server.js
const http = require('http')
const fs = require('fs')
http.createServer((req,res) => {
console.log('url',req.url)
const html =fs.readFileSync('../test.html','utf8')
res.writeHead(200,{
"Content-Type": "text/html"
})
res.end(html)
}).listen(8888)
// server2.js
const http = require('http')
http.createServer((req,res) => {
res.end('123')
}).listen(8887)
// test.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>
let xhr = new XMLHttpRequest()
xhr.open('GET','http://127.0.0.1:8887')
xhr.send()
</script>
</body>
</html>
1.分别用node运行server.js和server2.js,可以看到跨域了。
2.在server2.js中加入cors,来解决跨域
const http = require('http')
http.createServer((req,res) => {
// cors解决跨域
res.writeHead(200,{
"Access-Control-Allow-Origin":'*'
})
res.end('123')
}).listen(8887)
3.通过jsonp解决跨域,利用script标签的src属性运行跨域
<!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>
<script src="http://127.0.0.1:8887"></script>
</body>
</html>
cors预请求:
允许方法:
get
post
head
允许Content-Type:
text/plain
Multipart/form-data
Application/x-www-form-urlencoded
其他限制:
请求头限制
1.自定义请求头
<script>
fetch('http://127.0.0.1:8887',{
method:'PUT',
headers:{
'X-TEST-CORS':'123'
}
})
</script>
服务端没做处理,会报错。
解决方法:服务端加上请求头
res.writeHead(200,{
"Access-Control-Allow-Origin":'*',
"Access-Control-Allow-Headers":'X-TEST-CORS', // 请求头
})
2.使用除了get post head方法,比如put请求
<script>
fetch('http://127.0.0.1:8887',{
method:'PUT',
headers:{
'X-TEST-CORS':'123'
}
})
</script>
服务端没做处理,会报错。
解决方法:服务端加上请求方法
res.writeHead(200,{
"Access-Control-Allow-Origin":'*',
"Access-Control-Allow-Headers":'X-TEST-CORS',
"Access-Control-Allow-Methods":'POST,PUT,DELETE', // 加上允许的方法
})
缓存:
Cache-Control:
public:
private:只有发起请求的浏览器才可以进行缓存
No-cache:不允许进行缓存
Max-age = 1000ms 过期时间
举例:
<script src="/script.js"></script>
// server.js
const http = require('http')
const fs = require('fs')
http.createServer((req,res) => {
console.log('url',req.url)
if(req.url === '/'){
const html =fs.readFileSync('../test.html','utf8')
res.writeHead(200,{
"Content-Type": "text/html"
})
res.end(html)
}
// 不加Cache-Control
if(req.url === '/script.js'){
res.writeHead(200,{
"Content-Type": "text/javascript",
})
res.end('console.log("script loaded")')
}
}).listen(8888)
加缓存:
const http = require('http')
const fs = require('fs')
http.createServer((req,res) => {
console.log('url',req.url)
if(req.url === '/'){
const html =fs.readFileSync('../test.html','utf8')
res.writeHead(200,{
"Content-Type": "text/html"
})
res.end(html)
}
if(req.url === '/script.js'){
res.writeHead(200,{
"Content-Type": "text/javascript",
'Cache-Control':'max-age = 20' // 加缓存
})
res.end('console.log("script loaded")')
}
}).listen(8888)
加完缓存后,下次读取js文件就可以从缓存中读取,更快。
如果更新了js文件,但是如果缓存时间设置过长,url没改变,还是会从缓存中读取,导致代码没有更新。
解决办法:每次打包后给文件名加上hash。
Cache-Control还可以添加其他头:
'Cache-Control':'max-age = 20, public ' // 其他属性往后加就行
缓存策略:
Last-Modified:
1.上次修改时间
2.配合If-Modified-Since或者If-Unmodified-Since使用
3.对比上次修改时间来判断资源是否需要更新
Etag:
数据签名
配合If-Match
对比资源的签名判断是否使用缓存
使用:
1.将max-age调大,同时设置no-cache,允许浏览器一直访问服务器
2.设置’Last-Modified’:’123’,
3.设置’Etag’:’999’,
// server.js
if(req.url === '/script.js'){
res.writeHead(200,{
"Content-Type": "text/javascript",
'Cache-Control':'max-age = 20000000,no-cache',
'Last-Modified':'123',
'Etag':'999',
})
res.end('console.log("script loaded")')
}
当第一次访问的时候,response headers就会带上上面三个头
当第二次访问的时候,request headers就会带上If-Modified-Since 和If-None-Match:来验证是否需要更新
当不需要更新的时候,服务器不用返回任何内容,下面做下修改:
if(req.url === '/script.js'){
const e_tag = req.headers['if-none-match']
// 命中缓存
if(e_tag === '999'){
res.writeHead(304,{
"Content-Type": "text/javascript",
'Cache-Control':'max-age = 20000000,no-cache',
'Last-Modified':'123',
'Etag':'999',
})
res.end('')
}else{
res.writeHead(200,{
"Content-Type": "text/javascript",
'Cache-Control':'max-age = 20000000,no-cache',
'Last-Modified':'123',
'Etag':'999',
})
res.end('console.log("script loaded")')
}
}
做了一上修改,当第一次访问时:
1.状态码为200
2.返回有值:
当第二次访问时:
1.状态码为304
2.并且也返回了内容:
3.但是在代码里没有返回内容,所以浏览器从缓存中 读取了数据
cookei和session:
cookie属性:
1.max-age和expires设置过期时间
max-age:过期时间
expires:到什么时间点过期
2.Secure只在https的时候发送
3.HttpOnly无法通过document.cookie访问
设置cookie
const http = require('http')
const fs = require('fs')
http.createServer((req,res) => {
console.log('url',req.url)
if(req.url === '/'){
const html =fs.readFileSync('./test.html','utf8')
res.writeHead(200,{
"Content-Type": "text/html",
'Set-cookie':"id=123" // 设置cookie
})
res.end(html)
}
}).listen(8888)
第一次访问,response headers设置cookie
第二次访问,request headers就会带上cookie
nodejs设置多个cookie:
'Set-cookie':['id=123','name=aaa']
nodejs设置cookie过期时间:2s后id=123就没了
'Set-cookie':['id=123;max-age = 2','name=aaa']
设置HttpOnly:js就不能访问name=aaa了
'Set-cookie':['id=123;max-age = 2','name=aaa; HttpOnly']
长链接
Connection: keep-alive默认长链接
Connection:close关闭长链接
数据协商
Accept:
Accept-Encoding:gzip
const http = require('http')
const fs = require('fs')
const zlib = require('zlib')
http.createServer((req,res) => {
const html =fs.readFileSync('./test.html')
res.writeHead(200,{
"Content-Type": "text/html",
})
res.end(zlib.gzipSync(html)) // 使用zlib
}).listen(1111)
Accept-Language:zh-CN
User-Agent:浏览器信息
Content:
Content-Type
Content-Encoding
Content-Language
Redirect
const http = require('http')
const fs = require('fs')
http.createServer((req,res) => {
const html =fs.readFileSync('./test.html','utf8')
// 302临时重定向
// 301永久重定向
if(req.url === '/'){
res.writeHead(302,{
'Location':'/new'
})
res.end('')
}
if(req.url === '/new'){
res.writeHead(200,{
"Content-Type": "text/html",
})
res.end('<div>111</div>')
}
}).listen(2222)
csp
nginx
/usr/local/etc/nginx
http2
信道复用
分帧传输
server push