五层协议只是OSI和TCP/IP的综合,实际应用还是TCP/IP的四层结构。
TCP(Transmission Control Protocol)传输控制协议
TCP/IP协议将应用层、表示层、会话层合并为应用层,物理层和数据链路层合并为网络接口层
GET
, HEAD
, POST
, PUT
,DELETE
, TRACE
, OPTIONS
客服端和服务端在进行http请求和返回的工程中,需要创建一个
TCP connection
(由客户端发起),http不存在连接这个概念,它只有请求和响应。请求和响应都是数据包,它们之间的传输通道就是TCP connection
。
位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)Sequence number(顺序号码) Acknowledge number(确认号码)
第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;(第一次握手,由浏览器发起,告诉服务器我要发送请求了)
第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包;(第二次握手,由服务器发起,告诉浏览器我准备接受了,你赶紧发送吧)
第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功;(第三次握手,由浏览器发送,告诉服务器,我马上就发了,准备接受吧)
谢希仁著《计算机网络》中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。
URI: Uniform Resource Identifier/统一资源标识符 URL: Uniform Resource Locator/统一资源定位器 URN: Uniform Resource Name/永久统一资源定位符
web上的各种资源(html、图片、视频、音频等)都由一个URI标识定位。URI相当于它们的详细“家庭住址”。
URI包含了URL和URN。
URL是URI的一种,不仅标识了Web 资源,还指定了操作或者获取方式,同时指出了主要访问机制和网络位置。
URN是URI的一种,用特定命名空间的名字标识资源。使用URN可以在不知道其网络位置及访问方式的情况下讨论资源。
网上的一个例子:
// 这是一个URI
http://bitpoetry.io/posts/hello.html#intro
// 资源访问方式
http://
// 资源存储位置
bitpoetry.io/posts/hello.html
#intro // 资源
// URL
http://bitpoetry.io/posts/hello.html
// URN
bitpoetry.io/posts/hello.html#intro
请求报文:
响应报文:
curl命令是一个利用URL规则在命令行下工作的文件传输工具。它支持文件的上传和下载,所以是综合传输工具,但按传统,习惯称curl为下载工具。作为一款强力工具,curl支持包括HTTP、HTTPS、ftp等众多协议,还支持POST、cookies、认证、从指定偏移处下载部分文件、用户代理字符串、限速、文件大小、进度条等特征。做网页处理流程和数据检索自动化,curl可以祝一臂之力。
curl 访问 baidu.com
:
返回的内容中,html部分只有一个meta标签,<meta http-equiv="refresh" content="0;url=http://www.baidu.com/">
,这是因为我们访问的是baidu.com
,在浏览器中,浏览器会自动解析这个meta标签并重定向到http://www.baidu.com/
,然而命令行中并没有解析的功能。
curl 访问 www.baidu.com
:
-v
显示详细的请求信息
-X
指定请求方式
curl -X GET www.xxxx.com/xx/xx?xx=123
curl -X POST www.xxxx.com/xx/xx?xx=123
-o / -O
保存下载的文件
// 将文件下载到本地并命名为mygettext.html
curl -o mygettext.html http://www.gnu.org/software/gettext/manual/gettext.html
// 将文件保存到本地并命名为gettext.html
curl -O http://www.gnu.org/software/gettext/manual/gettext.html
// server1.js
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.js
const http = require('http')
http.createServer(function (request, response) {
console.log('request come', request.url)
response.end('123')
}).listen(8887)
console.log('server listening on 8887')
// test.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>
</body>
<script>
fetch('http://127.0.0.1:8887');
</script>
</html>
处理方法: 1.服务器端处理
// server2.js 服务器端设置允许跨域
response.writeHead(200, {
'Access-Control-Allow-Origin': '*' // * 表示任何域名下都可以访问这个服务,也可以指定域名
})
2.jsonp
// test.html
<script src="http://127.0.0.1:8887"></script>
就算存在跨域,请求还是会发送,响应也会返回,只是浏览器端发现了存在跨域问题就将返回内容屏蔽了,并报错提示。
// test.html
<script>
fetch('http://127.0.0.1:8887',{
method: 'post',
headers: {
'X-Test-Cors': '123'
}
});
</script>
我们设置的请求头中X-Test-Cors在跨域请求的时候,不被允许。
虽然不允许跨域,但是请求仍然会发送,并返回成功。
默认允许的请求方法:
其他的方法(PUT、DELETE)都需要预请求验证的。
默认允许的Content-Type
:
怎样设置允许我们设置的请求头:
// server2.js
response.writeHead(200, {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'X-Test-Cors' // 加上这个设置
})
首先发送一个预请求,预请求就是告诉浏览器接下来要发送的post请求是被允许的。
设置允许的请求方法:
// server2.js
response.writeHead(200, {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'X-Test-Cors',
'Access-Control-Allow-Methods': 'POST, PUT, DELETE'
})
设置一个安全时间:
// server2.js
response.writeHead(200, {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'X-Test-Cors',
'Access-Control-Allow-Methods': 'POST, PUT, DELETE',
'Access-Control-Max-Age': '1000'
})
Access-Control-Max-Age
的单位是秒,意思就是在多少秒以内,我们设置的这些允许的请求头,请求方法,是不需要发送预请求验证的,直接就可以通过,并发送。
常用值:
// 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,public' // 缓存20s 多个值用逗号分开
})
response.end('console.log("script loaded")')
}
}).listen(8888)
console.log('server listening on 8888')
// test.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>
</body>
<script src="/script.js"></script>
</html>
刷新会发现script.js
是从缓存中获取的,请求时间也是0。
我们希望浏览器缓存我们的图片,文件、js代码,但是服务器端代码更新了,浏览器端还是在缓存中获取的旧的文件。这就诞生了,webpack打包中出现的文件名后加上hash值,当文件改变时hash值也改变,这样浏览器就会发送新的请求到服务器端。
验证头:
上次修改时间 配合If-Modified-Since或者If-Unmodified-Since使用 对比上次修改时间以验证资源是否需要更新
数据签名(内容修改,签名就会改变) 配合If-Match或者If-Non-Match使用 对比资源的签名判断是否使用缓存
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')
302临时跳转,301永久跳转,301从缓存种获取跳转,使用301之后,主动权就掌握在用户手里,如果用户不清理缓存,那就算服务器端改变了也没用。
阮一峰:Content Security Policy 入门教程
HTTPS和HTTP的区别主要为以下四点: 一、https协议需要到ca申请证书,一般免费证书很少,需要交费。 二、http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。 三、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。 四、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。