文章目录
面试时回答
TCP协议是什么
TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,数据在传输前要建立连接,传输完毕后还要断开连接。连接时要经过三次握手,断开时要经过四次挥手的过程。
- TCP的三次握手
- 第一次握手:客户端发送一段TCP报文,服务端收到报文。
这次握手,服务端可以确认自己可以接受到客户端发送的报文 - 第二次握手:服务器端返回一段TCP报文,客户端收到返回报文。
这次握手,客户端可以确认服务端收到了自己发送的报文段,并且可以确认自己可以接受 服务器发送的报文段 - 第三次握手:客户端将返回的报文返回给服务端
这次握手,服务端可以确认客户端收到了自己发送的报文
客户端和服务端都需要确认各自可收、发,因此需要三次握手。
- TCP的四次挥手
-
第一次:
浏览器发送FIN码给服务器
,表示我要断开链接。 -
第二次:
服务器接收到后,并发送ACK码给浏览器
,表示已经收到你的断开请求。 -
第三次:
之后,服务器不会立刻就断开,会去确认所有要发送的数据是否已经发送完毕。 之后服务器继续发送FIN+ACK码
,告诉浏览器我的数据发送完毕。 -
第四次:
浏览器接收到后,确认下所有数据都接收完毕,之后会发送ACK码给服务器
,表示我已接收到你的信息了,我断开了,你也可以断开连接了。
为什么是建立连接是三次握手,而断开却是四次挥手
三次握手,主要是为了确认双方可以收到对方所传递过来的数据
。
四次挥手,断开时,其中**多了一步**就是确认自己要发送的数据已经发送完毕,对方确定自己要接收的数据也已经接收完毕,最终才会断开
,也就是多了第三次挥手的过程。
HTTPS与HTTP
https=http+ssl
,之所以能保证安全,主要原理是利用了非对称加密算法
,平常用的对称加密算法之所以不安全,是因为双方是用到统一的密钥进行加密解密的,只要双方有任何一方泄漏了密钥,那么其他人就可以利用密钥解密数据。客户端如何验证证书的合法性
1、校验证书的颁发机构是否受客户端信任。
2、通过 CRL 或 OCSP 的方式校验证书是否被吊销。
3、证书是否在有效期内。
4、判断网站域名是否与证书颁发的域名一致。
当前证书是自签的,还是权威机构颁发的
什么是对称加密
对称加密
,就是加密(encryption)与解密(decryption)用的是同样的密钥。
缺点
在发送密钥的过程中,密钥有很大的风险会被黑客们拦截,容易泄露。
解决办法
对密钥进行非对称加密,然后传送给需要它的人。
什么是非对称加密?
非对称加密
,它使用了一对密钥,公钥 和 私钥。
私钥只能由一方安全保管,不能外泄,而公钥则可以发给任何请求它的人。通过使用公钥加密,私钥解密。
比如,你向银行请求公钥,银行将公钥发给你,你使用公钥对消息加密,那么只有私钥的持有人–银行才能对你的消息解密。与对称加密不同的是,银行不需要将私钥通过网络发送出去,因此安全性大大提高。
TCP和UDP的区别
1、TCP 通讯双方建立连接的状态,才开始传递数据,一旦断开,则不再传输。适用于对安全性要求比较高的数据!
2、UDP 一方开始推送数据,不管另一方是否在接收,只管推送。适用于对安全性要求不高的数据。
HTTP协议是什么
HTTP 就是超文本传输协议
, 是一个专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范
。
一个http请求分为以下7个步骤
1,建立TCP连接
2,浏览器向服务器发送请求命令
3,浏览器向服务器发送请求头信息
4,服务器响应
5,服务器向浏览器发送响应头信息
6,服务器向浏览器发送数据
7,服务器关闭TCP连接
一个http请求一般由4个部分组成
1,http请求的方式,常见的有get和post
2,请求的url
3,请求头信息,包括一些浏览器信息和用户身份信息等
4,请求正文,包括一些用户的查询信息,表单信息等。请求头和请求体有一个空行来分开。
请求头信息包括
- origin: 从哪个地址发出的请求,但是仅仅包括协议和域名。
可以看到response有对应的header:Access-Control-Allow-Origin
- refer:从哪个地址发出的请求
- cookies:如果是同源的话,浏览器会自动携带cookie
- Authorization:授权信息
- user-agent:用户使用的客户端版本等信息
- accept 指定客户端可以接收的数据类型有哪些
- Content-Type: 表示客户端发送的数据类型
application/x-www-form-urlencoded、
application/form-data、
application/json、
application/octet-stream(二进制流数据)、
application/xml
响应码分五种类型,由它们的第一位数字表示:
1xx:请求已经接收到,需要进一步处理才能完成
2xx:成功处理请求
-
200 OK:成功返回响应
-
202 Accepted:服务器接受并开始处理请求,但请求未处理完成
3xx:重定向,就是通过各种方法将各种网络请求转到其它位置
- 301 ------ 请求的资源被永久的移动了位置
- 302------- 请求的资源被临时的移动了位置
- 304------- 针对GET 请求的资源,自上次访问以来并没有改变,则服务器应当
返回304,表示通过浏览器缓存读取该资源即可
。 - 305------ 所请求的资源必须通过代理访问
4xx:客户端错误,请求包含语法错误或者请求无法实现
- 400 Bad Request:服务器认为客户端出现了错误,但不明确,一般是 HTTP 请求格式错误
- 401 Unauthorized:用户认证信息缺失或者不正确,比方说没有携带token/ authorization等标识用户身份的东西。
- 403 Forbidden:禁止执行,一般是没有权限引起的。
- 404 Not Found:服务器没有找到对应的资源
- 405 Method Not Allowed ------ 请求方法不正确,比如说应该是post,而你用的是get
- 412 ------ 请求头字段的错误
- 413 ------ 请求的资源大于服务器允许的大小
- 414 ------ 请求地址URL大于服务器允许的长度
5xx:服务器错误
- 500 Internal Server Error ------ 服务器内部错误
- 501 ------ 服务器不支持请求的功能,无法完成请求
- 502 Bad Gateway ------ 网关或者代理服务器无响应
- 505 HTTP Version Not Supported ------ 请求使用的 HTTP版本不支持
HTTP与TCP的区别和联系
TCP对应于传输层,HTTP对应于应用层,从本质上来说,二者没有可比性。
Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求。Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的。所以Http连接是一种短连接,是一种无状态的连接。
TCP是底层协议,定义的是数据传输和连接方式
的规范。
HTTP是应用层协议,定义的是传输数据的内容
的规范。
结论:
HTTP协议中的数据是利用TCP协议传输的,所以支持HTTP就一定支持TCP。
XMLHTTPRequest对象
常用方法
- open(请求方法:“get/post”, 请求url, 是否异步(默认true))
- send(请求体发送数据,无则传入null)
- abort():收到响应之前取消异步请求
- setRequestHeader(‘MyHeader’, ‘MyValue’)
- getResponseHeader(‘MyHeader’)|getAllResponseHeader()
属性
- responseText
- responseXML
- status(响应HTTP状态)
- statusText(响应HTTP状态描述)
- readyState(响应状态,请求/响应过程的哪个阶段):0未初始化|1已打开|2已发送|3接收中|4完成,从一个值变为一个值,会触发readystatechange事件,
- readystatechange事件处理程序应该在调用open()之前赋值
- timeout超时时间,对应超时事件ontimeout
- 进度事件:
loadstart、progress事件
示例
let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain/service');
// request state change event
xhr.onreadystatechange = function () {
// request completed?
if (xhr.readyState !== 4) return;
if (xhr.status === 200) {
// request successful - show response
console.log(xhr.responseText);
} else {
// request error
console.log('HTTP error', xhr.status, xhr.statusText);
}
};
xhr.timeout = 3000; // 3 seconds
xhr.ontimeout = () => console.log('timeout', xhr.responseURL);
// progress事件可以报告长时间运行的文件上传
xhr.upload.onprogress = p => {
console.log(Math.round((p.loaded / p.total) * 100) + '%');
}
// start request
xhr.send(null);
fetch
-
方法:
fetch(url,{}init对象)
,返回Promise对象,只支持异步。 -
响应通过response对象获取:
fetch().then((response)=>{}).catch(()=>{})
,response对象混入了body,提供了5个方法,将ReadableStream转存到缓冲区的内存里,将缓冲区转换为js对象,通过Promise返回。- response.text() //转为text
- response.json() //转为json
- response.formData()
- response.arrayBuffer()
- response.blob()
-
错误不会reject:当接收到一个代表错误的 HTTP 状态码时,从 fetch()返回的 Promise 不会被标记为 reject, 即使该 HTTP 响应的状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的 ok 属性设置为 false ),
仅当网络故障时或请求被阻止时,才会标记为 reject
-
不支持超时设置
-
需要借用
AbortController终止fetch
-
fetch示例
fetch( 'http://domain/service', { method: 'GET' } ) .then(response => response.json()) .then(json => console.log(json)) .catch(error => console.error('error:', error)); //credentials:omit不发送cookie|same-origin同源发送cookie(默认)|include都发送cookie fetch( 'http://domain/service', { method: 'GET', credentials: 'same-origin' } ) // 错误不会reject // HTTP错误(例如404 Page Not Found 或 500 Internal Server Error)不会导致Fetch返回的Promise标记为reject;.catch()也不会被执行。 // 想要精确的判断 fetch是否成功,需要包含 promise resolved 的情况,此时再判断 response.ok是不是为 true fetch( 'http://domain/service', { method: 'GET' } ) .then(response => { if (response.ok) { return response.json(); } throw new Error('Network response was not ok.'); }) .then(json => console.log(json)) .catch(error => console.error('error:', error)); // 不支持直接设置超时, 可以用promise function fetchTimeout(url, init, timeout = 3000) { return new Promise((resolve, reject) => { fetch(url, init) .then(resolve) .catch(reject); setTimeout(reject, timeout); }) } // 中止fetch // signal用于支持AbortController中断请求 const controller = new AbortController(); //AbortController接口表示一个控制器对象,允许你根据需要中止一个或多个 Web请求。 fetch( 'http://domain/service', { method: 'GET', signal: controller.signal }) .then(response => response.json()) .then(json => console.log(json)) .catch(error => console.error('Error:', error)); controller.abort();
请求体的数据格式
-
form-data
:
就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件
。当上传的字段是文件时,会有Content-Type来说明文件类型;
content-disposition,用来说明字段的一些信息;
由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。 -
x-www-form-urlencoded
:就是application/x-www-from-urlencoded,会将表单内的数据转换为键值对,比如,name=java&age = 23 -
json
: 也就是Content-Type:application/json,上传JSON格式的数据; -
octet-stream
:也就是Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。 -
raw
:可以上传任意格式的文本,可以上传text、json、xml、html
等
XHR请求过程
1、XMLHTTPRequest对象
var xhr = new XMLHttpRequest()
2、请求信息配制(请求方式,请求地址,是否异步,请求头信息、监听请求)
// 请求方式、地址、是否异步
xhr.open(method,url,asncy)
// 请求头信息
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
// 请求成功回调函数
xhr.onload = e => {
console.log('request success');
};
// 请求结束
xhr.onloadend = e => {
console.log('request loadend');
};
// 请求出错
xhr.onerror = e => {
console.log('request error');
};
// 请求超时
xhr.ontimeout = e => {
console.log('request timeout');
};
3、发送请求
xhr.send(params)
具体详解
最简单的http请求
let xhr = new XMLHttpRequest();
xhr.open('GET', '/url', true);
xhr.send();
封装XMLHttpRequest
const http = {
/**
* js封装ajax请求
* >>使用new XMLHttpRequest 创建请求对象,所以不考虑低端IE浏览器(IE6及以下不支持XMLHttpRequest)
* >>使用es6语法,如果需要在正式环境使用,则可以用babel转换为es5语法 https://babeljs.cn/docs/setup/#installation
* @param settings 请求参数模仿jQuery ajax
* 调用该方法,data参数需要和请求头Content-Type对应
* Content-Type data 描述
* application/x-www-form-urlencoded 'name=哈哈&age=12'或{name:'哈哈',age:12} 查询字符串,用&分割
* application/json name=哈哈&age=12' json字符串
* multipart/form-data new FormData() FormData对象,当为FormData类型,不要手动设置Content-Type
* 注意:请求参数如果包含日期类型.是否能请求成功需要后台接口配合
*/
ajax: (settings = {}) => {
// 初始化请求参数
let _s = Object.assign({
url: '', // string
type: 'GET', // string 'GET' 'POST' 'DELETE'
dataType: 'json', // string 期望的返回数据类型:'json' 'text' 'document' ...
async: true, // boolean true:异步请求 false:同步请求 required
data: null, // any 请求参数,data需要和请求头Content-Type对应
headers: {}, // object 请求头
timeout: 1000, // string 超时时间:0表示不设置超时
beforeSend: (xhr) => {
},
success: (result, status, xhr) => {
},
error: (xhr, status, error) => {
},
complete: (xhr, status) => {
}
}, settings);
// 参数验证
if (!_s.url || !_s.type || !_s.dataType || !_s.async) {
alert('参数有误');
return;
}
// 创建XMLHttpRequest请求对象
let xhr = new XMLHttpRequest();
// 请求开始回调函数
xhr.addEventListener('loadstart', e => {
_s.beforeSend(xhr);
});
// 请求成功回调函数
xhr.addEventListener('load', e => {
const status = xhr.status;
if ((status >= 200 && status < 300) || status === 304) {
let result;
if (xhr.responseType === 'text') {
result = xhr.responseText;
} else if (xhr.responseType === 'document') {
result = xhr.responseXML;
} else {
result = xhr.response;
}
// 注意:状态码200表示请求发送/接受成功,不表示业务处理成功
_s.success(result, status, xhr);
} else {
_s.error(xhr, status, e);
}
});
// 请求结束
xhr.addEventListener('loadend', e => {
_s.complete(xhr, xhr.status);
});
// 请求出错
xhr.addEventListener('error', e => {
_s.error(xhr, xhr.status, e);
});
// 请求超时
xhr.addEventListener('timeout', e => {
_s.error(xhr, 408, e);
});
let useUrlParam = false;
let sType = _s.type.toUpperCase();
// 如果是"简单"请求,则把data参数组装在url上
if (sType === 'GET' || sType === 'DELETE') {
useUrlParam = true;
_s.url += http.getUrlParam(_s.url, _s.data);
}
// 初始化请求
xhr.open(_s.type, _s.url, _s.async);
// 设置期望的返回数据类型
xhr.responseType = _s.dataType;
// 设置请求头
for (const key of Object.keys(_s.headers)) {
xhr.setRequestHeader(key, _s.headers[key]);
}
// 设置超时时间
if (_s.async && _s.timeout) {
xhr.timeout = _s.timeout;
}
// 发送请求.如果是简单请求,请求参数应为null.否则,请求参数类型需要和请求头Content-Type对应
xhr.send(useUrlParam ? null : http.getQueryData(_s.data));
},
// 把参数data转为url查询参数
getUrlParam: (url, data) => {
if (!data) {
return '';
}
let paramsStr = data instanceof Object ? http.getQueryString(data) : data;
return (url.indexOf('?') !== -1) ? paramsStr : '?' + paramsStr;
},
// 获取ajax请求参数
getQueryData: (data) => {
if (!data) {
return null;
}
if (typeof data === 'string') {
return data;
}
if (data instanceof FormData) {
return data;
}
return http.getQueryString(data);
},
// 把对象转为查询字符串
getQueryString: (data) => {
let paramsArr = [];
if (data instanceof Object) {
Object.keys(data).forEach(key => {
let val = data[key];
// todo 参数Date类型需要根据后台api酌情处理
if (val instanceof Date) {
// val = dateFormat(val, 'yyyy-MM-dd hh:mm:ss');
}
paramsArr.push(encodeURIComponent(key) + '=' + encodeURIComponent(val));
});
}
return paramsArr.join('&');
}
}
说一说你对 DNS 的理解
-
DNS (Domain Name System) 负责
对域名的解析
工作,由根DNS服务器
、顶级DNS 服务器
和权威 DNS 服务器
组成。 -
解析顺序是首先从
浏览器缓存
、操作系统缓存
以及本地 DNS 缓存
(/etc/hosts) 逐级查找,然后从本地 DNS 服务器
、根 DNS
、顶级 DNS
以及权威 DNS
层层递归查询。
说一说你对 CDN 的理解
-
CDN(Content Delivery Network)就是
内容分发网络
。 -
为了突破现实生活中的传输距离等物理限制,
CDN
投入了大量资金,在全球范围内各大枢纽城市建立机房
,部署大量高存储高带宽的节点,构建跨运营商、跨地域的专用高速传输网络
。 -
在用户接入网络后,首先
通过全局负载均衡
(Global Sever Load Balance),简称 GSLB 算法负责调度,找到离用户最合适的节点
。然后通过 HTTP 缓存代理技术进行缓存,缓存命中就返回给用户,否则就回源站去取。CDN 擅长缓存静态资源(图片、音频等),当然也支持动态内容的缓存。
参考地址 https://www.jianshu.com/p/918c63045bc3