OSI 与TCP/IP模型
输入域名发生了什么
假设输入 www.baidu.com
浏览器解析域名。
客户端与服务端进行数据交互的时候,不能识别域名,通过DNS解析域名转化未对用的IP地址
- 浏览器缓存中查找是否存在映射关系
- 查询·本地host文件,查看是否存在域名与ip的对应关系,有的话则直接解析出来ip
- host文件不存在,就去本地区的DNS服务器(移动联通电信运营商提供的dns)里面查找ip与域名是否有映射关系,有的话返回
- 还没找到的话去根服务器查找
- 根服务器会判断这个域名由谁管理,这里
.com
就由负责.com
的顶级域名服务器管理,然后返回这个服务器的ip。顶级域名服务器(gTLD Server): .com、.cn等域名 - 本地区的dns服务器会向这个顶级域名服务器的ip继续查询,他返回域名对应的域名服务器,这个域名服务器是你注册的域名服务器,这个域名的服务商的服务器将承担起域名解析的任务。
- 域名服务器将解析出的ip返回给本地区的服务器
- 本地区的服务器缓存解析结果
- 将解析的结果返回给用户
TCP/IP三次握手建立连接
引出一个问题:为什么是三次?两次建立连接存在什么问题?四次呢
- 第一次握手,客户端的TCP向服务端的TCP发送连接请求报文,
SYN=1
(SYN代表发起一个新连接),和一个随机的起始信号seq=x
(seq信号,32位,用于标识TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记) - 第二次握手,服务端TCP接收到请求报文之后,向客户机发送请求,并为该TCP连接分配TCP缓存和变量,他向客户端发送四个字段:
SYN=1
、ACK=1
(确认信号是有效的) 、ack=x+1
(ack序号,32位,只有在ACK标志位置1时,ack才是有效的,ack=seq+1)、随机产生一个的一个seq=y
- 客户机收到确认的报文时,需要继续向服务端确认,并且也要给该链接分配缓存和变量
ACK=1
、seq=x+1
、ack=y+1
几种状态的说明:
- CLOSED:连接结束,没有任何连接状态
- LISTEN:监听远端的连接,可以接收连接
- SYN_SENT:客户端连接时,发送SYN之后进入SYN_SENT状态
- SYN_REVD:服务端接收到了客户端发送的SYN报文
- ESTABLISHED:标识已经成功建立TCP连接
浏览器客户端向后端发送数据
- 三次握手建立连接之后,向后台发送请求
后台返回数据给浏览器渲染
-
解析html结构,构建dom树,那所有的标签解析出来
-
构建cssom树,解析css样式
-
执行script标签中的代码(所以避免将该标签放在头部,造成页面空白,形成阻塞 )
- 普通标签:解析到
script
标签之后,加载脚本内容,然后执行,执行完毕之后继续解析html - defer:解析到
script
之后,不发生阻塞,一边解析html,一遍加载脚本,等带html解析全部解析完成之后,在执行脚本 - async:与defer相似,只是脚本执行的时机不同,他在加载脚本时不发生阻塞,等待叫脚本加载完成之后,执行脚本
- 普通标签:解析到
-
将dom和cssom合并成渲染树
-
根据渲染树将页面绘制出来
四次挥手断开连接
引出一个问题:三次挥手行不行
- 第一次挥手,客户端发送一个连接释放报文,并停止再发送数据,主动关闭TCP连接,
FIN=1
(释放一个连接),seq=u
- 第二次挥手: 服务器接收连接释放报文后即发出确认,
ACK=1
、ack=u+1
、seq=v
此时, 从客户机到服务器这个方向的连接就释放了, TCP连接处于半关闭状态. 但服务器若发送数据, 客户机仍要接收, 即从服务器到客户机的连接仍未关闭. - 第三次挥手: 若服务器已经没有了要向客户机发送的数据, 就通知TCP释放连接, 此时其发出FIN=1的连接释放报文
FIN=1
、ACK=1
、seq=w
、ack=u+1
- 第四步: 客户机收到连接释放报文后, 必须发出确认. 在确认报文中, ACK字段被置为1, 确认号ack=w+1, 序号seq=u+1. 此时, TCP连接还没有释放掉, 必须经过等待计时器设置的时间2MSL(MSL:报文的最大生存时间)后, 客户端才进入到连接关闭状态.
几种状态得说明:
-
FIN_WAIT_1客户端发送FIN=1得关闭连接得的请求之后进入该状态
-
CLOSE_WAIT :服务端收到客户端发送得关闭连接的请求后,确认信号是有效的,回应客户端之后进入
-
FIN_WAIT_2:客户端收到服务端响应的ACK之后进入。进入半关闭的状态,只能客户端只能接受数据,不能发送数据
-
LAST_ACK:服务端发送一个FIN关闭信号给客户端,等待对方确认
-
TIME_WAIT:客户端接收到服务端发送的FIN关闭信号之后进入,等待足够的时间2MSL,以此确保客户端收到确认关闭连接的ACK
-
CLOSED:连接结束
TCP与UDP协议
- UDP协议:UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。
- TCP协议:TCP协议全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。T
UDP | TCP | |
---|---|---|
是否连接 | 无连接,不用关心对方是否接收到 | 面向连接,需要确保双方建立正确的连接 |
是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
连接对象个数 | 支持一对一,一对多,多对一和多对多交互通信 | 只能是一对一通信 |
首部开销 | 首部开销小,仅8字节 | 首部最小20字节,最大60字节 |
适用场景 | 适用于实时应用(IP电话、视频会议、直播等),速度要求快 | 适用于要求可靠传输的应用,例如文件传输 |
HTTP
无状态的,以请求/应答方式运行的协议,她使用可拓展的语义和自描述消息格式,与基于网络的超文本信息系统(html页面)灵活的互动
- 无状态的:不会去存储用户的信息
- 请求/应答:发送请求===>得到相应
- 可拓展:在协议的基础可以对请求头部添加一些字段
- 自描述:可以传输文本、图片等格式
请求类型
-
get:参数挂载在url上,只被用于获取数据
-
post:将实体提交到指定的资源,侧重于新增数据
-
put:侧重于修改数据 ,整体更新
-
patch:对put方法的额外补充,用于局部更新
-
delete:删除指定资源
-
head:与get相同,但是只返回响应头,没有响应主体
-
options:预检请求,检查服务器支持哪些http方法,响应体中包含一个
Allow
字段,包含了所支持的方法 -
connect:创建一个客户端与请求资源之间双向通信的隧道,点对点通信
-
trace:服务端原样返回接收到的信息,提供了一种用于debug方法
RESTful请求风格
RESTful是面向资源请求,url中不能存在动词,只能有名词。
https://api.example.com/v1/zoos
对于具体资源的操作,HTTP提供了上面的请求类型,可以使用这些动词来表对资源进行哪些操作,对于一些参数,比如:获取Tom的数学成绩,用get请求来写的话,请求地址就是/tom?subject=math
,但是用RESTful风格来写就是/tom/math
,列出一些常用例子:
//方法 接口 行为
GET /zoos: 列出所有动物园
POST /zoos: 新建一个动物园
GET /zoos/ID: 获取某个指定动物园的信息
PUT /zoos/ID: 更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID: 更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID: 删除某个动物园
GET /zoos/ID/animals: 列出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID: 删除某个指定动物园的指定动物
axios里面同样提供了这些请求方法的别名
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
请求头
-
Accept 浏览器可接受的数据格式
-
Accept-Encoding 浏览器可接收的压缩算法,如 gzip
-
Accept-lanuage 浏览器能接收的语言
-
Connection: keep-alive 一次TCP连接重复使用(一次连接,多次使用)
-
cookie 非跨域请求都会带上
-
Host请求的域名
-
User-Agent(简称 UA)发出请求的客户端,浏览器信息
-
Content-type 发送方数据的格式,如application/json
- application/json :转化成json字符串形式
- multipart/form-data: post 传输文件
- application/x-www-form-urlencoded :form表单默认格式,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字符串(name1=value1&name2=value2)然后把这个字串append到url后面,用?分割,加载这个新的url。 当action为post时候,浏览器把form数据封装到http body中,然后发送到server。
HTTPS
- 在HTTP协议通信的基础上,使用SSL/TLS为网络通信提供安全及数据完整性的一种安全协议,对网络连接进行加密
WebSocket
跨域问题
原因
- 同源策略:协议,域名,端口号都相同的话,则称之为同源,为了保证用于信息的安全,不同源的情况下,下面的行为会受到限制:
- cookie,localStorage,indexDB无法读取
- 无法获取DOM
- 请求的响应被浏览器拦截
解决方案
jsonp
img
、link
、script
标签不受同源策略的影响。jsonp本质是动态创建script
标签,利用他不产生跨域的特点,向后台发送请求
- 前端先声明一个请求成功之后的回调函数 sayName`
- 前端创建
script
标签,后台接收到请求之后,通过一些处理返回一个函数名,并且把数据当作参数放进去,返回sayName('Tom')
- 请求成功之后数据会被放进去,执行
sayName
script
加载资源发送的请求是get请求,以至于jsonp也有这个局限。
node中间件代理
同源策略仅仅是浏览器的限制,对于服务器之间的相互请求则不做限制
例如这里,前端需要向localhost:5000
请求数据。项目npm run dev
运行的时候,在本地启动了一个服务4000,前端发送请求的时候会经由4000,然后他再向5000发送请求,4000向5000转发请求不涉及跨域,请求成功之后,5000给4000返回响应,然后4000再转发给前端
- 使用vue开发项目时,不可避免的要遇到跨域问题,通常去配置脚手架中的
proxyTable
(根据脚手架版本),这里就是利用了中间件,本地启动一个服务,所有的请求都发送到本地创建的服务,然后由他转发给后台
- react跨域问题同样用也可以用这个方法解决
CORS
跨域资源共享,关键实现在于服务端。
Access-COntrol-Allow-Origin
:关键属性,要么是请求时Origin
字段的值,要么是一个*
,表示接受任意域名的请求。Access-Control-Allow-Credentials
:默认为false
,表明请求是否携带credentials(代表cookies, authorization headers 或 TLS client certificates),Credentials必须在前后端都被配置(即后台Access-Control-Allow-Credentials
和 前端XHR 或Fetch request中都要配置)才能使带credentials的CORS请求成功。如果决定要发送cookie,那么Access-Control-Allow-Origin
属性不能设置成*
,必须指定必须的,于请求一致的域名origin
Access-Control-Expose-Headers
:出现在响应头中,暴露出来的响应头,供XMLHttpRequest对象的getResponseHeader()获取额外的头部信息Access-Control-Allow-Methods
:出现在预检请求的响应中,表明服务端支持跨域的方法Access-Control-Allow-Headers
:出现在预检请求的响应中,表示服务端支持的所有头部信息,如果请求头设置了Access-Control-request-Header
,那么该字段必需。Access-Control-Max-Age
:出现在预检请求的响应头中,表示预检请求的有效期,单位秒,在这个时间内不在发送预检请求Access-Control-Request-Method
:必选,出现在预检请求的请求头中,表示真正请求实会采用那种请求方法Access-Control-Request-Header
:出现在预检请求的请求头中,表示服务器在真正的请求中会采用哪些请求头
Nginx反向代理
配置nginx的nginx.conf
文件
浏览器访问 http://localhost:81
时,转发到 https://mywebsite.com
server {
#访问的端口号
listen 81;
#访问的地址
server_name localhost;
location / {
root html;
index index.html index.htm;
#转发的地址
proxy_pass https://mywebsite.com;
}
}
HTTP缓存
向服务器请求数据时,会又优先查询浏览器缓存,如果缓存中存在需要请求的数据,就直接从浏览器缓存中提取出来数据,常见的http缓存只能缓存get请求响应的资源
-
http缓存分类:根据是否重新向服务器发起请求来分类,可分为强缓存和协商缓存
-
http缓存过程:
- 第一步:浏览器第一次请求数据,服务端返回资源,在响应头中添加资源的缓存参数。
- 第二步:判断请求的数据,查看是否命中强缓存,如果命中,则返回状态码200,从浏览器获取资源,请求不会被发送到服务端
- 第三步:未命中强缓存,则向服务器发送请求,服务器会对 比缓存是否失效了,是否更新了,如果资源更新了则返回状态码200,从服务器获取资源,并且更新缓存,如果判断发现未更新,则返回状态码304,然后去浏览器中获取资源
强制缓存
强制缓存在缓存未过期的情况下,即Cache-Control的max-age属性
或者Expires
未过期,那么就会去返回浏览器的缓存,强制缓存生效时,http状态码是200,这种方式是页面加载速度最快的,因为他没有与服务器进行交互。但是假如在服务器的资源被修改了,这时候拿到的缓存就不是我们预期的数据了,页面上刷新了但没有生效,因为走的是强制缓存,所以Ctrl + F5一顿操作之后就好了。 跟强制缓存相关的header头属性有(Pragma/Cache-Control/Expires)
相关属性:
Cache-Control
:no-store
:禁止任何缓存策策略,请求时服务器都要响应一个新的资源no-cache
不使用强缓存,直接去使用协商缓存,与no-cache
互斥,同时设置时,以`no-store为准max-age
:代表一个相对的时间长度,相对于客户端时间,单位是秒,例如Cache-Control:max-age=31536000
,意味着在成功请求的31536000秒后过期,每次请求成功会延迟失效时间s-maxage
:代理服务器缓存有效时间,public
情况下有效private
:默认值,只能被浏览器缓存public
:可以被浏览器缓存,也可以被代理服务器缓存,
- Expires设置一个固定的时间,在这个时刻缓存过期,
Expires:Mon, 20 Jul 2017 10:08:35 GMT
,在这个时刻之前都是有效的,请求成功不会延时失效时间,一般情况下都是使用Cache-Control
协商缓存
响应头中没有Cache-Control和Expires或者Cache-Control和Expires过期还或者它的属性设置为no-cache时(即不走强缓存),那么浏览器第二次请求时就会与服务器进行协商(通过判断last-modified/if-modified-since是否一致
或者Etag/If-None-Match是否一致
),与服务器端对比判断资源是否进行了修改更新。服务端资源没有更改,则返回304.然后从浏览器获取资源,已更改则从服务器获取资源,返回200
实现协商缓存的两种方式:
Last-modified
:存在于响应头中,标识文件的最后修改时间If-modified-Since
:存在于请求头里面,值为之前返回的last-modified
上面一组属性可以解决大部分缓存情况,但是存在一些不足,他们的时间戳单位是秒,也就是说,如果发生修改资源的太快,在击几百毫秒之内完成,对于他们来说仍是相等的,无法识别出资源已经更新。另外也可能存在只改变文件名而不改变文件内容的情况,这种情况会被认定为资源更新,会去服务请资源而耗费性能。对于着二者的缺点,可以使用 Etag/If-None-Match
的方案优化
Etag
:存在于文件的哈希值,唯一的,资源改变会改变它的EtagIf-None-Match
:存在于请求头,值为之前返回的Etag
比较上面两种协商缓存的方案,他们都有一个共同流程,首次请求服务端返回一个标识放在响应头中,第二次及以后的请求都会将响应头的这个值放在请求头中,通过比较两个值来判断资源是否更改
这种方案并不能完全替代last-modified
,他只能作为一种补充,因为它同样存在一些不足,首先,文件的哈希值需要服务器去计算,对服务器造成了额外的开销,尤其对于一些大文件或者文件数目很多的情况,频繁计算文件哈希值造成了性能的而损耗。另外,生成etag的过程中存在精度问题,某些情况会造成比对失败
总结
- 缓存决策过程:
-
不同类型的文件缓存方案:
具体的缓存方案需要根据实际的开发场景来决定
- html文件需要及时的更新,需要设置成协商缓存
- 图片文件等媒体文件较大,可能会定期的替换更改,可以设置较短时间的强制缓存
- css样式文件,js脚本文件可以可以设置较长时间的强缓存
-
刷新页面的行为
- F5 刷新页面 仍然会去查找浏览器种的强缓存然后去找协商缓存
- Ctrl+F5 强制刷新
Cache-Control
会变成·no-chche
即不走强缓存
浏览器存储方案
cookie、localStorage、sessionStorage的使用
安全
XSS
跨站脚本攻击,向客户端插入脚本,用户打开网页或者点击某个按钮会运行注入的脚本
参考于美团技术团队: 如何防止XSS攻击
注入的情景
- 在 HTML 中内嵌的文本中,恶意内容以 script 标签形成注入。渲染文本时,后台返回的数据包含
script
标签
<h1>前端渲染后台返回的数据: <script>alert(1)</script> </h1>
- 在内联的 JavaScript 中,拼接的数据突破了原本的限制(字符串,变量,方法名等)。
<script>
let backendData = alert(1) //后端的数据
let data = backendData //前端对这些数据进行操作
console.log(data)
</script>
- 在标签属性中,恶意内容包含引号,从而突破属性值的限制,注入其他属性或者标签。
后台返回的数据 "><script>alert('XSS');</script>
<input type="text" value="<%= getParameter("keyword") %>">
拼接后:
<input type="text" value=""><script>alert('XSS');</script>">
- 在标签的 href、src 等属性中,包含
javascript:
等可执行代码。
后台返回的数据:javascript:alert('XSS')
<a href="<%= escapeHTML(getParameter("redirect_to")) %>">跳转...</a>
拼接后
<a href="javascript:alert('XSS')">跳转...</a>
- 在 onload、onerror、onclick 等事件中,注入不受控制代码。
- 在 style 属性和标签中,包含类似
background-image:url("javascript:...");
的代码(新版本浏览器已经可以防范)。 - 在 style 属性和标签中,包含类似
expression(...)
的 CSS 表达式代码(新版本浏览器已经可以防范)。
XSS分类
根据攻击的来源,XSS 攻击可分为存储型、反射型和 DOM 型三种。对于前两种,后端应该做好防护,而第三种DOM型需要前端防范
- 存储型:提交恶意代码到数据库中,用户打开页面时,从后台取出这些数据,然后拼接数据,浏览器渲染页面的时候会执行这些代码,常见于评论,私信,发布文章等场景
- 反射型:构造出特殊的URL,用户点击跳转这个URL时,恶意代码也被解析执行。常见于通过 URL 传递参数的功能,如网站搜索、跳转等。与存储型不同的是:存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里。
- DOM型:攻击者构造出特殊的 URL,用户打开带有恶意代码的 URL,恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作
如何防范
对于存储型和反射性
他们都是从后台取出恶意代码,然后再html中被拼接,被浏览器执行,有两种方法预防:
-
改成纯前端渲染,把代码和数据分隔开。这在很多内部、管理系统中常用
- 浏览器先加载一个静态 HTML,此 HTML 中不包含任何跟业务相关的数据。
- 然后浏览器执行 HTML 中的 JavaScript。
- JavaScript 通过 Ajax 加载业务数据,调用 DOM API 更新到页面上。明确的告诉浏览器:下面要设置的内容是文本(
.innerText
),还是属性(.setAttribute
),还是样式(.style
)等等。浏览器不会被轻易的被欺骗,执行预期外的代码了
-
对 HTML 做充分转义。采用合适的转义库,如 doT.js、ejs、FreeMarker 等,对 HTML 模板各处插入点进行充分的转义。把一些关键字符力例如
& < > " ' /
等转义掉,HTML 的编码是十分复杂的,在不同的上下文里要使用相应的转义规则
对于DOM型
- DOM型是因为页面把不可信的数据当成了代码执行,所以在使用
.innerHTML
、.outerHTML
、document.write()
时要特别小心,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用.textContent
、.setAttribute()
等,对于Vue/React 技术栈,尽量不使用v-html
/dangerouslySetInnerHTML
功能,在前端 render 阶段避免innerHTML
、outerHTML
的 XSS 隐患。DOM 中的内联事件监听器,如location
、onclick
、onerror
、onload
、onmouseover
等,<a>
标签的href
属性,JavaScript 的eval()
、setTimeout()
、setInterval()
等,都能把字符串作为代码运行。如果不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患,
其他防范措施
- 对要提交的输入内容做长度限制
- 对cookie设置http-only属性,禁止前端浏览器读取cookie
- 验证码:防止脚本冒充用户提交危险操作
CSRF
参考美团技术团队 如何防止CSRF攻击
跨站请求伪造,引导用户进入第三方网站中,然后发送请求,冒充用户身份,对被攻击的网站执行某些操作,
常见攻击类型
- GET请求类型,进入第三方网站后,浏览器请求图片资源,然后发送向被攻击网站发送请求
//从 bank.example 中拿到用户cookie
<img style="0;" src="http://bank.example/withdraw?amount=10000&for=hacker" >
- POST请求,进入第三发放网站自动提交表单发送一个post请求
<form method="POST" action="https://bank.example/xxx" enctype="multipart/form-data">
<input type="hidden" name="name" value="xiaoming"/>
<input type="hidden" name="amount" value="10000"/>
</form>
<script>
document.forms[0].submit();
</script>
- 跳转连接,诱导用户点击页面中的链接,在连接中伪造请求
<a href="http://bank.example/withdraw?amount=10000&for=hacker" taget="_blank">重磅消息!! <a/>
如何防范
CSRF只是冒用cookie,并不能获取到cookie的实际值,另外,CSRF通常发生在第三方网站
同源检测
- Origin(只有协议、域名、端口号。不包含路径的详细信息) 或者Referer(协议、域名、端口号、参数。页面来源的详细地址)。包含了请求的来源信息,可以判断请求的来源,禁排除掉外域(或者不受信任的域名)的请求操作
SameSite属性
SamesiteCookie是一个可能替代同源验证的方案,但目前还并不成熟,其应用场景有待观望。
SameSite=None
不做限制,浏览器会在同站请求、跨站请求下继续发送 cookiesSameSite=Strict
:只在访问相同站点时发送 cookieSameSite=Lax
:假如这个请求是这种请求(改变了当前页面或者打开了新页面)且同时是个GET请求,则这个Cookie可以作为第三方Cookie
JWT验证
- 后端根据用户生成一个Token,然后把Token返回给前端,前端保存Token
- 调用其他接口进行交互时,新增一个请求头字段,放Token
- 后台接收到Token时比验证Token是否一致
其他防范措施
- get请求不要包含增改删功能,仅查询数据
- 对于用户来说,尽量避免打开可疑链接,或者用不常用的浏览器打开
攻击者诱导受害者进入第三方网站,再第三方的网站中,向被攻击的网站发送请求,由于再第三方网站中,用户存在cookie,已经完成身份验证,所以在
Fetch
参考文档 :使用Fetch
Fetch作为一种Http请求方案,是XHR的代替方案,注意Fetch是基于Promise原生的API,而Axios是基于Promise的库,Fetch使用方法与Axios十分类似,注意post请求时,fetch传递的时body属性,值是对象转化成字符串JSON.stringify(data)
拓展
TCP三次握手连接的原因
首先要知道TCP三次握手的目的是什么:为了确保双方的发送和接收能力都是正常且可靠的
- 不能采用两次握手的原因:结合三次握手的流程图来看,去掉第二次握手----服务端向客户端的响应的话,客户端不能确认服务端是否具有正常的发送功能,额外举个例子:客户端显示发送了一个连接请求,但是由于某些原因导致他一致在传输的路上,没有被客户端收到。这个时候客户端会认为这个请求是不是发送出错了,然后又给客户端发送了一条连接请求,然后巧了,客户端收到了这个请求,双方于是建立了连接,传输了数据,然后断开了连。然而这个时候客户端发送的第一条连接请求终于到了,服务端收到了,于是又建立了连接,造成服务端资源的浪费
- 不采取四次握手的原因:三次握手完全足够双方确认是否能够正常收发信息,不需要额外的握手交互了
TC四次挥手的原因
- 客户端在发送断开连接的请求·
FIN
之后,服务端并不能及时的响应断开连接的请求FIN
,必须等到服务端所有的报文都发送完毕,这个过程需要一定时间。去除第二次服务端给客户端的回应的话,期间等待服务端发送完毕的过程中,长时间没回应的话,客户端会认为丢包,然后又给服务端发了一个FIN关闭请求,这时就会出现问题。
正向代理与反向代理
正向代理是客户端和其他所有服务器(重点:所有)的代理者,而反向代理是客户端和反向代理服务器所代理的服务器之间的代理(也就是说反向代理有可能代理2个服务器,3个服务器等)
- 正向代理:多个用户向代理服务器发送请求,然后转发给一个目标服务器,比如 FQ提子
- 反向代理:一个用户向代理服务器发送请求,然后代理服务器推断请求,发送到多个服务器中的一个