计算机网络
- 一篇就够:[https://juejin.im/post/5ad7e6c35188252ebd06acfa](https://juejin.im/post/5ad7e6c35188252ebd06acfa)
- 从请求到响应过程详解:
- TCP/IP超级详解
- 简单总结:
- 网络模型数据处理过程
- 域名的空间结构:
- 跨域
- 跨域的解决方案
- 代理和网关
- Cookie 与 Session
- Session与Token
- cookie与token
- cookie、localstroage、sessionstroage的区别
- HTTP的几种请求方法用途
- HTTP状态码及其含义
- 常见的HTTP状态码
- http 和 https 有何区别?如何灵活使用?
- 重定向
- WebSocket
- XMLHTTP
- XMLhttprequest详解。
- AJAX
- Axios
- Web安全
一篇就够:https://juejin.im/post/5ad7e6c35188252ebd06acfa
从请求到响应过程详解:
https://juejin.im/post/5b1265edf265da6e155d45a9
1、首先,在浏览器地址栏中输入url
2、浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。若没有,则跳到第三步操作。
3、在发送http请求前,需要域名解析(DNS解析)(DNS(域名系统,Domain Name System)是互联网的一项核心服务,
它作为可以将域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网,而不用去记住IP地址。),解析获取相应的IP地址。
4、浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手。(TCP即传输控制协议。TCP连接是互联网连接协议集的一种。)
5、握手成功后,浏览器向服务器发送http请求,请求数据包。
6、服务器处理收到的请求,将数据返回至浏览器
TCP/IP超级详解
https://juejin.im/post/5a069b6d51882509e5432656#heading-24
简单总结:
计算机网络体系解构:
tcp udp区别:
tcp 三次握手:
为什么TCP建立连接需三次握手?
防止服务器端因接收了早已失效的连接请求报文,从而一直等待客户端请求,最终导致形成死锁、浪费资源
四次挥手
为什么TCP释放连接需四次挥手?
为了保证通信双方都能通知对方 需释放 & 断开连接
网络模型数据处理过程
域名的空间结构:
跨域
含义
跨域是指一个域下的文档或脚本试图去请求另一个域下的资源
会造成跨域的行为
1.) 资源跳转: A链接、重定向、表单提交
2.) 资源嵌入: <link>、<script>、<img>、<frame>等dom标签,还有样式中background:url()、@font-face()等文件外链
3.) 脚本请求: js发起的ajax请求、dom和js对象的跨域操作等
同源策略
什么是同源策略?
同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
同源策略限制以下几种行为:
1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM 节点
3.) AJAX 请求可以被发送,但是会被浏览器拦截
但是有三个标签是允许跨域加载资源:
<img src=XXX>
<link href=XXX>
<script src=XXX>
跨域的解决方案
https://segmentfault.com/a/1190000011145364
https://juejin.im/post/5c23993de51d457b8c1f4ee1
- jsonp:只支持GET,不支持POST请求,不安全XSS
- postMessage:配合使用iframe,需要兼容IE6、7、8、9
- document.domain:仅限于同一域名下的子域
- cors:需要后台配合进行相关的设置
- websocket:需要后台配合修改协议,不兼容,需要使用socket.io
- proxy:使用代理去避开跨域请求,需要修改nginx、apache等的配置
- window.name + iframe跨域
jsonp(服务器与客户端跨源)
详解:https://segmentfault.com/a/1190000007935557
为什么需要jsonp
-
首先,因为ajax无法跨域,然后开发者就有所思考
-
其次,开发者发现,
<script>
标签的src属性是可以跨域的把跨域服务器写成 调用本地的函数 ,回调数据回来不就好了? -
json刚好被js支持(object,调用跨域服务器上动态生成的js格式文件(不管是什么类型的地址,最终生成的返回值都是一段js代码)
-
这种获取远程数据的方式看起来非常像ajax,但其实并不一样
-
便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP。
-
传递一个callback参数给跨域服务端,然后跨域服务端返回数据时会将这个callback参数作为函数名来包裹住json数据即可。
什么是jsonp
- jsonp浏览器对script标签src属性、link标签ref属性和img标签src属性没有同源策略限制,利用这个“漏洞”就可以很好的解决跨域请求,JSONP就是利用了script标签无同源限制的特点来实现的。
- 当向第三方站点请求时,我们可以将此请求放在script标签的src属性里,这就如同请求一个普通的JS脚本,可以自由的向不同的站点请求。
- 通过将前端方法作为参数传递到服务器端,然后由服务器端注入参数之后再返回,实现服务器端向客户端通信。
- 由于使用script标签的src属性,因此只支持get方法
JSONP 的原理是什么?
JSONP 的原理:
-
通过 script 标签加载数据的方式去获取数据当作 JS 代码来执行;
-
请求的脚本网址有一个callback参数(?callback=bar),用来告诉服务器,客户端的回调函数名称(bar)
-
服务器收到请求后,拼接一个字符串,将 JSON 数据放在函数名里面,作为字符串返回
-
客户端会将服务器返回的字符串,作为代码解析,因为浏览器认为,这是
实现流程:
实现流程
-
设定一个script标签
-
callback定义了一个函数名,而远程服务端通过调用指定的函数并传入参数来实现传递参数,将fn(response)传递回客户端
$callback = !empty($_GET['callback']) ? $_GET['callback'] : 'callback';
echo $callback.'(.json_encode($data).)';
- 客户端接收到返回的js脚本,开始解析和执行fn(response)
代码实现
简单实现:
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
document.head.appendChild(script);//document.body.appendChild(script);
// 回调执行函数
function handleCallback(res) {
alert(JSON.stringify(res));
}
</script>
promise封装
//创建script发送请求
//请求返回执行cb函数,并且删除创建的script
//类似于$ajax中的jsonp
function jsonp(url,params,cb){
return new Promimse((resolve,reject)=>{
window[cb] = function(data){
resolve(data);
document.body.removeChild(script);
}
params={...params,cb},
let arrs=[];
for(let key in params){
arrs.push(`${key}=${params[key]}`)
}
let script = document.createElement('script');
script.src= url + '?'+ arrs.join('&');
document.body.appendChild(script);
})
}
jsonp({
url:'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su',
params:{wd:%E8%B7%A8%E5%9F%9F},
cb:'show'}).then(data=>{
console.log(data)
})
document.domain(跨网页)
此方案仅限主域相同,子域不同的跨域应用场景
1.)父窗口:(http://www.domain.com/a.html)
<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
document.domain = 'domain.com';
var user = 'admin';
</script>
2.)子窗口:(http://child.domain.com/b.html)
document.domain = 'domain.com';
// 获取父窗口中变量
alert('get js data from parent ---> ' + window.parent.user);
location.hash 解决 iframe跨域(跨窗口)
-
网页可以使用iframe元素,嵌入其他网页,因此一个网页之中会形成多个窗口。如果子窗口之中又嵌入别的网页,就会形成多级窗口。如果跨域,就无法拿到对方的 DOM。
-
不同域之间利用iframe的location.hash传值
-
片段标识符(fragment identifier)指的是,URL 的#号后面的部分,比如http://example.com/x.html#fragment的#fragment。如果只是改变片段标识符,页面不会重新刷新。
-
父窗口可以把信息,写入子窗口的片段标识符。
var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;
上面代码中,父窗口把所要传递的信息,写入 iframe 窗口的片段标识符。
- 子窗口通过监听hashchange事件得到通知。
window.onhashchange = checkMessage;
function checkMessage() {
var message = window.location.hash;
// ...
}
- 同样的,子窗口也可以改变父窗口的片段标识符。
parent.location.href = target + '#' + hash;
window.postMessage()(跨窗口)
简介
- HTML5为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源
- 它可用于解决以下方面的问题:
a.) 页面和其打开的新窗口的数据传递
b.) 多窗口之间消息传递
c.) 页面与嵌套的iframe消息传递
用法
- postMessage(data,origin)方法接受两个参数
data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
example
1.)a.html:(http://www.domain1.com/a.html)
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
var iframe = document.getElementById('iframe');
iframe.onload = function() {
var data = {
name: 'aym'
};
// 向domain2传送跨域数据
iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
};
// 接受domain2返回数据
window.addEventListener('message', function(e) {
alert('data from domain2 ---> ' + e.data);
}, false);
</script>
2.)b.html:(http://www.domain2.com/b.html)
<script>
// 接收domain1的数据
window.addEventListener('message', function(e) {
alert('data from domain1 ---> ' + e.data);
var data = JSON.parse(e.data);
if (data) {
data.number = 16;
// 处理后再发回domain1
window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
}
}, false);
</script>
WebSocket
-
WebSocket 是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
-
下面是一个例子,浏览器发出的 WebSocket 请求的头信息(摘自维基百科)。
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
-
上面代码中,有一个字段是Origin,表示该请求的请求源(origin),即发自哪个域名。
-
正是因为有了Origin这个字段,所以 WebSocket 才没有实行同源政策。因为服务器可以根据这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器就会做出如下回应。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
跨域资源共享(CORS)
-
对于开发者来说,CORS 通信与普通的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感知。因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨域通信。
-
普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
-
- 需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。
example
前端设置
- ajax
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端设置是否带cookie
xhr.withCredentials = true;
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
- axios
axios.defaults.withCredentials = true
服务端设置
- java后台
/*
* 导入包:import javax.servlet.http.HttpServletResponse;
* 接口参数中定义:HttpServletResponse response
*/
// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");
// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
- Nodejs后台示例
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
var postData = '';
// 数据块接收中
req.addListener('data', function(chunk) {
postData += chunk;
});
// 数据接收完毕
req.addListener('end', function() {
postData = qs.parse(postData);
// 跨域后台设置
res.writeHead(200, {
'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie
'Access-Control-Allow-Origin': 'http://www.domain1.com', // 允许访问的域(协议+域名+端口)
/*
* 此处设置的cookie还是domain2的而非domain1,因为后端也不能跨域写cookie(nginx反向代理可以实现),
* 但只要domain2中写入一次cookie认证,后面的跨域接口都能从domain2中获取cookie,从而实现所有的接口都能跨域访问
*/
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly的作用是让js无法读取cookie
});
res.write(JSON.stringify(postData));
res.end();
});
});
server.listen('8080');
console.log('Server is running at port 8080...');
其他跨域
九种跨域方式详解https://segmentfault.com/a/1190000011145364
代理和网关
- 代理是一种有转发功能的应用程序,它扮演了位于服务器和客户端’中间人’的角色,接收客户端发送的请求不改变请求的URI并转发给服务器,同时也接收服务器返回的相应并转发客户端
- 缓存代理:代理转发响应时会预先将资源缓存在代理服务器上当代理再次接收到对相同资源的请求时,就可以不从源服务器那里获取资源,而是将之前缓存的资源作为响应返回
- 透明代理:转发请求或响应时,不对报文做任何加工的代理类型
- 网关是转发其他服务器通信数据的服务器,接收从客户端发送来的请求时,它就像自己拥有资源的源服务器一样对请求进行处理,其工作机制和代理类似,而网关能使通信线路上的服务器提供非HTTP协议的服务。
反向代理
大家都有过这样的经历,拨打10086客服电话,可能一个地区的10086客服有几个或者几十个,你永远都不需要关心在电话那头的是哪一个,叫什么,男的,还是女的,漂亮的还是帅气的,你都不关心,你关心的是你的问题能不能得到专业的解答,你只需要拨通了10086的总机号码,电话那头总会有人会回答你,只是有时慢有时快而已。那么这里的10086总机号码就是我们说的反向代理。客户不知道真正提供服务人的是谁。
反向代理隐藏了真实的服务端,当我们请求
www.baidu.com 的时候,就像拨打10086一样,背后可能有成千上万台服务器为我们服务,但具体是哪一台,你不知道,也不需要知道,你只需要知道反向代理服务器是谁就好了,www.baidu.com 就是我们的反向代理服务器,反向代理服务器会帮我们把请求转发到真实的服务器那里去。Nginx就是性能非常好的反向代理服务器,用来做负载均衡。
负载均衡和动静分离
- 负载均衡是反向代理的一种,后端多台服务器,nginx根据权重、压力、带宽的分配服务器,避免等待和拥塞
- 动静分离是反向代理的一种,后端服务器分为动态资源服务器和静态资源服务器,nginx会根据请求分配服务器,区分处理逻辑,加快响应
Cookie 与 Session
Session与Token
Session是一种HTTP储存机制, 为无状态的HTTP提供持久机制;
Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。
Token就是令牌, 比如你授权(登录)一个程序时,它就是个依据,判断你是否已经授权该软件;
Session和Token并不矛盾,作为身份认证Token安全性比Session好,因为每一个请求都有签名还能防止监听以及重放攻击,而Session就必须依赖链路层来保障通讯安全了。如上所说,如果你需要实现有状态的回话,仍然可以增加Session来在服务端保存一些状态。
cookie与token
https://www.jianshu.com/p/ce9802589143
token相对cookie的优势
- 无状态
基于token的验证是无状态的,这也许是它相对cookie来说最大的优点。后端服务不需要记录token。每个令牌都是独立的,包括检查其有效性所需的所有数据,并通过声明传达用户信息。服务器唯一的工作就是在成功的登陆请求上签署token,并验证传入的token是否有效。 - 防跨站请求伪造(CSRF)
举个CSRF攻击的例子,在网页中有这样的一个链接[外链图片转存失败(img-BIjtCdfp-1566703950744)(http://bank.com?withdraw=1000&to=tom)]
,假设你已经通过银行的验证并且cookie中存在验证信息,同时银行网站没有CSRF保护。一旦用户点了这个图片,就很有可能从银行向tom这个人转1000块钱。但是如果银行网站使用了token作为验证手段,攻击者将无法通过上面的链接转走你的钱。(因为攻击者无法获取正确的token) - 多站点使用
cookie绑定到单个域。foo.com域产生的cookie无法被bar.com域读取。使用token就没有这样的问题。这对于需要向多个服务获取授权的单页面应用程序尤其有用。使用token,使得用从myapp.com获取的授权向myservice1.com和myservice2.com获取服务成为可能。 - 支持移动平台
好的API可以同时支持浏览器,iOS和Android等移动平台。然而,在移动平台上,cookie是不被支持的。 - 性能
一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算的Token验证和解析要费时得多。
cookie、localstroage、sessionstroage的区别
https://juejin.im/post/5caac97c5188251169093efe
-
Cookie适合存储一些session信息:
cookie限制大小,约4k左右,不适合存储业务数据,尤其是数据量较大的值存在有效期,到期自动销毁
cookie会每次随http请求一起发送,浪费宽
cookie设置了domain可以在子域共享跨域
可以使用爬虫抓取 -
localstroage适合存储应用共享的地址信息等:
存储数据量大,5M或者更大
有效期为永久
不会随http请求一起发送
不能跨域,但是可以使用postMessage和iframe消除这个影响,例如:cross-storage
在浏览器的隐私模式下不能读取
不能被爬虫读取 -
sessionstroage适合存储浏览状态等:
可以跨域
存储数据量大,5M或者更大
有效期为到浏览器关闭
不会随http请求一起发送
不能被爬虫读取
-indexDB
key/object,可以存储对象,浏览器中的数据库,异步,支持事务,和域名绑定,存储空间大
HTTP的几种请求方法用途
-
GET方法
发送一个请求来取得服务器上的某一资源 -
POST方法
向URL指定的资源提交数据或附加新的数据 -
PUT方法
跟POST方法很像,也是想服务器提交数据。但是,它们之间有不同。PUT指定了资源在服务器上的位置,而POST没有 -
HEAD方法
只请求页面的首部 -
DELETE方法
删除服务器上的某资源 -
OPTIONS方法
它用于获取当前URL所支持的方法。如果请求成功,会有一个Allow的头包含类似“GET,POST”这样的信息 -
TRACE方法
TRACE方法被用于激发一个远程的,应用层的请求消息回路 -
CONNECT方法
把请求连接转换到透明的TCP/IP通道
get与post
同:
异:
- GET 和 POST 只是 HTTP 协议中两种请求方式,而 HTTP 协议是基于 TCP/IP 的应用层协议,无论 GET 还是 POST,所以GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET产生的URL地址可以被Bookmark,而POST不可以。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的,而POST么有。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中。
HTTP状态码及其含义
1XX:信息状态码
100 Continue 继续,一般在发送post请求时,已发送了http header之后服务端将返回此信息,表示确认,之后发送具体参数信息
2XX:成功状态码
200 OK 正常返回信息
201 Created 请求成功并且服务器创建了新的资源
202 Accepted 服务器已接受请求,但尚未处理
3XX:重定向
301 Moved Permanently 请求的网页已永久移动到新位置。
302 Found 临时性重定向。
303 See Other 临时性重定向,且总是使用 GET 请求新的 URI。
304 Not Modified 自从上次请求后,请求的网页未修改过。
4XX:客户端错误
400 Bad Request 服务器无法理解请求的格式,客户端不应当尝试再次使用相同的内容发起请求。
401 Unauthorized 请求未授权。
403 Forbidden 禁止访问。
404 Not Found 找不到如何与 URI 相匹配的资源。
5XX: 服务器错误
500 Internal Server Error 最常见的服务器端错误。
503 Service Unavailable 服务器端暂时无法处理请求(可能是过载或维护)。
常见的HTTP状态码
- 200(“OK”)
一切正常。实体主体中的文档(若存在的话)是某资源的表示。 - 500(“Bad Request”)
客户端方面的问题。实体主题中的文档(若存在的话)是一个错误消息。希望客户端能够理解此错误消息,并改正问题。 - 500(“Internal Server Error”)
服务期方面的问题。实体主体中的文档(如果存在的话)是一个错误消息。该错误消息通常无济于事,因为客户端无法修复服务器方面的问题。 - 301(“Moved Permanently”)
当客户端触发的动作引起了资源URI的变化时发送此响应代码。另外,当客户端向一个资源的旧URI发送请求时,也发送此响应代码。 - 404(“Not Found”) 和410(“Gone”)
当客户端所请求的URI不对应于任何资源时,发送此响应代码。404用于服务器端不知道客户端要请求哪个资源的情况;410用于服务器端知道客户端所请求的资源曾经存在,但现在已经不存在了的情况。 - 409(“Conflict”)
当客户端试图执行一个”会导致一个或多个资源处于不一致状态“的操作时,发送此响应代码。
http 和 https 有何区别?如何灵活使用?
http是HTTP协议运行在TCP之上。所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份。
https是HTTP运行在SSL/TLS之上,SSL/TLS运行在TCP之上。所有传输的内容都经过加密,加密采用对称加密,但对称加密的密钥用服务器方的证书进行了非对称加密。此外客户端可以验证服务器端的身份,如果配置了客户端验证,服务器方也可以验证客户端的身份
重定向
URL 重定向,也称为 URL 转发,是一种当实际资源,如单个页面、表单或者整个 Web 应用被迁移到新的 URL 下的时候,保持(原有)链接可用的技术。HTTP 协议提供了一种特殊形式的响应—— HTTP 重定向(HTTP redirects)来执行此类操作,该操作可以应用于多种多样的目标:网站维护期间的临时跳转,网站架构改变后为了保持外部链接继续可用的永久重定向,上传文件时的表示进度的页面,等等。
WebSocket
https://www.cnblogs.com/jiangzhaowei/p/8781635.html
由于 http 存在一个明显的弊端(消息只能有客户端推送到服务器端,而服务器端不能主动推送到客户端),导致如果服务器如果有连续的变化,这时只能使用轮询,而轮询效率过低,并不适合。于是 WebSocket被发明出来
相比与 http 具有以下有点
支持双向通信,实时性更强;
可以发送文本,也可以二进制文件;
协议标识符是 ws,加密后是 wss ;
较少的控制开销。连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有2~10字节(取决于数据包长度),客户端到服务端的的话,需要加上额外的4字节的掩码。而HTTP协议每次通信都需要携带完整的头部;
支持扩展。ws协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议。(比如支持自定义压缩算法等)
无跨域问题。
实现比较简单,服务端库如 socket.io、ws,可以很好的帮助我们入门。而客户端也只需要参照 api 实现即可
XMLHTTP
定义
- XMLHTTP 是一组API函数集,可被JavaScript、JScript、VBScript以及其它web浏览器内嵌的脚本语言调用,通过HTTP在浏览器和web服务器之间收发XML或其它数据。XMLHTTP最大的好处在于可以动态地更新网页,它无需重新从服务器读取整个网页,也不需要安装额外的插件。该技术被许多网站使用,以实现快速响应的动态网页应用。例如:Google的Gmail服务、Google Suggest动态查找界面以及Google Map地理信息服务。
- XMLHTTP是AJAX网页开发技术的重要组成部分。除XML之外,XMLHTTP还能用于获取其它格式的数据,如JSON或者甚至纯文本。—— 维基百科
- 最通用的定义为:XmlHttp是一套可以在Javascript、VbScript、Jscript等脚本语言中通过http协议传送或从接收XML及其他数据的一套API。XmlHttp最大的用处是可以更新网页的部分内容而不需要刷新整个页面。
- 来自MSDN的解释:XmlHttp提供客户端同http服务器通讯的协议。客户端可以通过XmlHttp对象(MSXML2.XMLHTTP.3.0)向http服务器发送请求并使用微软XML文档对象模型Microsoft® XML Document Object Model (DOM)处理回应。
XMLHTTP 实现
- ActiveXObject
IE中使用ActiveXObject方式创建XmlHttp对象 - XMLHttpRequest
Firefox、Opera等通过window.XMLHttpRequest来创建xmlhttp对象。
ActiveXObject
什么是 ActiveX 控件
- Microsoft ActiveX 控件是由软件提供商开发的可重用的软件组件。使用 ActiveX 控件,可以很快地在网址、台式应用程序、以及开发工具中加入特殊的功能。例如,StockTicker 控件可以用来在网页上即时地加入活动信息,动画控件可用来向网页中加入动画特性。
ActiveXObject 对象
- JavaScript 中 ActiveXObject 对象是启用并返回 Automation 对象的引用。
ActiveXObject 语法
newObj = new ActiveXObject(servername.typename[, location])
参数:
newObj
必选 - ActiveXObject 分配到的变量名称
servername
必选 - 提供对象的应用程序名称
typename
必选 - 要创建的对象的类型或类
location
可选 - 要再其中创建对象的网络服务器的名称
ActiveXObject 使用
// 在IE5.x和IE6下创建xmlHttp对象
// servername - MSXML2
// typename - XMLHTTP.3.0
var xmlHttp = new ActiveXObject('MSXML2.XMLHTTP.3.0');
xmlHttp.open("GET", "http://localhost/books.xml", false);
xmlHttp.send();
XMLHttpRequest
- XMLHttpRequest 是一个API, 它为客户端提供了在客户端和服务器之间传输数据的功能。它提供了一个通过 URL 来获取数据的简单方式,并且不会使整个页面刷新。这使得网页只更新一部分页面而不会打扰到用户。XMLHttpRequest 在 AJAX 中被大量使用。
- XMLHttpRequest 是一个 JavaScript 对象,它最初由微软设计,随后被 Mozilla、Apple 和 Google采纳. 如今,该对象已经被 W3C组织标准化. 通过它,你可以很容易的取回一个URL上的资源数据. 尽管名字里有XML, 但 XMLHttpRequest 可以取回所有类型的数据资源,并不局限于XML。 而且除了HTTP ,它还支持file 和 ftp 协议。
XMLhttprequest详解。
- XMLHttpRequest:XMLHttpRequest是XMLHttp组件的一个JavaScript 对象,使用XMLHttpRequest可以实现浏览器端与服务器端进行异步通信。
- 通过HttpRequest对象,Web应用程序无需刷新页面就可以向服务器提交信息,然后得到服务器端的返回信息
- Ajax的核心是JavaScript对象XmlHttpRequest。XmlHttpRequest使您可以使用JavaScript向服务器提出请求并处理响应,而不阻塞用户。通过XMLHttpRequest对象,Web开发人员可以在页面加载以后进行页面的局部更新。
XMLHttpRequest对象的常用方法和属性。
方法:
- open(“method”,”URL”) 建立对服务器的调用,第一个参数是HTTP请求 方式可以为GET,POST或任何服务器所支持的您想调用的方式。 第二个参数是请求页面的URL。
- send()方法,发送具体请求
- abort()方法,停止当前请求
属性:
- readyState属性 请求的状态 有5个可取值0=未初始化 ,1=正在加载 2=以加载,3=交互中,4=完成
- responseText 属性 服务器的响应,表示为一个串
- reponseXML 属性 服务器的响应,表示为XML
- status 服务器的HTTP状态码,200对应ok 400对应not found
AJAX
什么是AJAX
AJAX即“Asynchronous JavaScript and XML”(异步的JavaScript与XML技术),指的是一套综合了多项技术的浏览器端网页开发技术。
Ajax所包含的技术
AJAX技术体系的组成部分有HTML,css,dom,xml,xmlHttpRequest,javascript
1.运用XHTML+CSS来表达信息;
2.运用JavaScript操作DOM(Document Object Model)来运行动态效果;
3.使用XMLHttpRequest来和服务器进行异步通信。(最重要)
4.运用XML和XSLT(XSLT 是一种用于将 XML 文档转换为 XHTML 文档或其他 XML 文档的语言。)或者JSON操作数据
Ajax的原理
简单来说通过XmlHttpRequest对象来向服务器发送异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面
Ajax的实现流程是怎样的?
详解:https://blog.csdn.net/qq_29569183/article/details/79259889
-
创建XMLHttpRequest对象,也就是创建一个异步调用对象.
-
创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
-
设置响应HTTP请求状态变化的函数.
-
发送HTTP请求.
-
获取异步调用返回的数据.
-
使用JavaScript和DOM实现局部刷新.
AJAX都有哪些优点和缺点?
Ajax的优点
1、最大的一点是页面无刷新,用户的体验非常好。
2、使用异步方式与服务器通信,具有更加迅速的响应能力。
3、可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。ajax的原则是“按需取数据”,可以最大程度的减少冗余请求,和响应对服务器造成的负担。
4、基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。
Ajax的缺点
1、ajax不支持浏览器back按钮。
2、安全问题 AJAX暴露了与服务器交互的细节。
3、对搜索引擎的支持比较弱。
4、破坏了程序的异常机制。
5、不容易调试。
Ajax请求与HTTP请求的区别
- AJAX通XMLHttpRequest对象请求服务器服务器接受请求返数据实现刷新交互
- AJAX请求头会多一个x-requested-with参数,值为XMLHttpRequest
- 普通http请求通httpRequest象请求服务器接受请求返数据需要页面刷新
- 传统的http请求的发起者对于是当前页面,浏览器接收到服务器的响应后要刷新整个页面(即使只有页面中的一小部分需要更新);发出的页面同时会处于不可用状态。
- xmlhttp请求的发起者可以是页面中的任何元素,浏览器接收到服务器的响应后传递给对应的处理函数,由该函数决定做什么。页面本身的显示和操作在请求和接收数据的过程中不受影响。
Ajax与websocket、http
websocket、ajax的出现解决的http协议的一些问题,但http依然在很多地方是好的有优势的,ajax是单向(客户端到服务端),http也是单向由客户端发起的,websocket实现了双向
Axios
Axios全攻略:https://ykloveyxk.github.io/2017/02/25/axios%E5%85%A8%E6%94%BB%E7%95%A5/#more
定义
- axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端
特征
- 从浏览器中创建 XMLHttpRequest
- 从 node.js 发出 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防止 CSRF/XSRF
让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
Axios简单封装
vue中Axios的封装和API接口的管理:https://juejin.im/post/5b55c118f265da0f6f1aa354
/**axios封装
* 请求拦截、相应拦截、错误统一处理
*/
import axios from 'axios';
import QS from 'qs';//引入qs模块,用来序列化post类型的数据
import { Toast } from 'vant';
import store from '../store/index'
// 环境的切换
if (process.env.NODE_ENV == 'development') {
axios.defaults.baseURL = '/api';//axios.defaults.baseURL可以设置axios的默认请求地址
} else if (process.env.NODE_ENV == 'debug') {
axios.defaults.baseURL = '';
} else if (process.env.NODE_ENV == 'production') {
axios.defaults.baseURL = 'http://api.123dailu.com/';
}
// 请求超时时间
axios.defaults.timeout = 10000;
// post请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
// 请求拦截器
axios.interceptors.request.use(
config => {
// 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
const token = store.state.token;
token && (config.headers.Authorization = token);
return config;
},
error => {
return Promise.error(error);
})
// 响应拦截器
axios.interceptors.response.use(
response => {
if (response.status === 200) {
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
},
// 服务器状态码不是200的情况
error => {
if (error.response.status) {
switch (error.response.status) {
// 401: 未登录
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
router.replace({
path: '/login',
query: { redirect: router.currentRoute.fullPath }
});
break;
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token和清空vuex中token对象
// 跳转登录页面
case 403:
Toast({
message: '登录过期,请重新登录',
duration: 1000,
forbidClick: true
});
// 清除token
localStorage.removeItem('token');
store.commit('loginSuccess', null);
// 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
setTimeout(() => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
}, 1000);
break;
// 404请求不存在
case 404:
Toast({
message: '网络请求不存在',
duration: 1500,
forbidClick: true
});
break;
// 其他错误,直接抛出错误提示
default:
Toast({
message: error.response.data.message,
duration: 1500,
forbidClick: true
});
}
return Promise.reject(error.response);
}
}
);
/**
* get方法,对应get请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function get(url, params){
return new Promise((resolve, reject) =>{
axios.get(url, {
params: params
})
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err.data)
})
});
}
/**
* post方法,对应post请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function post(url, params) {
return new Promise((resolve, reject) => {
axios.post(url, QS.stringify(params))
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err.data)
})
});
}
附注
process.env.NODE_ENV
- 在node中,有全局变量process表示的是当前的node进程。process.env包含着关于系统环境的信息。但是process.env中并不存在NODE_ENV这个东西。NODE_ENV是用户一个自定义的变量,在webpack中它的用途是判断生产环境或开发环境的依据的。
- 当使用 webpack 或 Browserify 类似的构建工具时,Vue 源码会根据 process.env.NODE_ENV 决定是否启用生产环境模式,默认情况为开发环境模式。在 webpack 与 Browserify 中都有方法来覆盖此变量,以启用 Vue 的生产环境模式,同时在构建过程中警告语句也会被压缩工具去除。所有这些在 vue-cli 模板中都预先配置好了,
- 在 webpack 4+ 中,你可以使用 mode 选项:
module.exports = {
mode: 'production'
}
Token
token,一般是在登录完成之后,将用户的token通过localStorage或者cookie存在本地,然后用户每次在进入页面的时候(即在main.js中),会首先从本地存储中读取token,如果token存在说明用户已经登陆过,则更新vuex中的token状态。然后,在每次请求接口的时候,都会在请求的header中携带token,后台人员就可以根据你携带的token来判断你的登录是否过期,如果没有携带,则说明没有登录过。这时候或许有些小伙伴会有疑问了,就是每个请求都携带token,那么要是一个页面不需要用户登录就可以访问的怎么办呢?其实,你前端的请求可以携带token,但是后台可以选择不接收啊!
Web安全
一篇够https://juejin.im/post/5ce55b3d5188253386140dd0
XSS 与 CSRF 有什么区别吗?
XSS 是获取信息,不需要提前知道其他用户页面的代码和数据包。
CSRF 是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。要完成一次 CSRF 攻击,受害者必须依次完成两个步骤:
- 登录受信任网站 A,并在本地生成 Cookie。
- 在不登出 A 的情况下,访问危险网站 B。
XSS(Cross Site Scripting):跨域脚本攻击。
XSS攻击详解:https://www.cnblogs.com/mao2080/p/9460397.html
xss详解:https://www.jianshu.com/p/4fcb4b411a66
原理
- 通过对网页注入可执行代码且成功地被浏览器 执行,达到攻击的目的,形成了一次有效XSS攻击
- xss漏洞通常是通过php的输出函数将javascript代码输出到html页面中,通过用户本地浏览器执行的,所以xss漏洞关键就是寻找参数未过滤的输出函数。
- 常见的输出函数有:
echo printf print print_r sprintf die var-dump var_export.
分类
反射型XSS(非持久化)
- 攻击者事先制作好攻击链接, 需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。
存储型XSS(持久化)
- 代码是存储在服务器中的,如在个人信息或发表文章等地方,加入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,
- 每当有用户访问该页面的时候都会触发代码执行,这种XSS非常危险,容易造成蠕虫,大量盗窃cookie(虽然还有种DOM型XSS,但是也还是包括在存储型XSS内)。
DOM型XSS
- 基于文档对象模型Document Objeet Model,DOM)的一种漏洞。
- DOM是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问和更新文档内容、结构和样式,处理后的结果能够成为显示页面的一部分。
- DOM中有很多对象,其中一些是用户可以操纵的,如uRI ,location,refelTer等。
- 客户端的脚本程序可以通过DOM动态地检查和修改页面内容,它不依赖于提交数据到服务器端,而从客户端获得DOM中的数据在本地执行,如果DOM中的数据没有经过严格确认,就会产生DOM XSS漏洞。
如何防御
- 最普遍的做法是转义输入输出的内容,对于引号,尖括号,斜杠进行转义
- 对于显示富文本来说,不能通过上面的办法来转义所有字符,因为这样会把需要的格式也过滤掉。这种情况通常采用白名单过滤的办法,当然也可以通过黑名单过滤,但是考虑到需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式
- 在设置Cookie时,加上HttpOnly参数
- CSP 白名单
CSP可以通过HTTP头部(Content-Security-Policy)或元素配置页面的内容安全策略,以控制浏览器可以为该页面获取哪些资源。:http://www.ruanyifeng.com/blog/2016/09/csp.html - 关于在vue中的xss防御
vue已经在框架中进行了一些xss防御了,我们对于一些外来的内容(例如接口或URL参数),尽量用{{ }}表达式来显示,因为{{ }}中的内容经过字符串化,浏览器不会对其中的内容进行执行操作。
尽量少用v-hmtl指令,或者先对内容进行xss过滤。虽然 HTML 5 中指定不执行由 innerHTML 插入的 “script” 标签。但是其中的标签是可以有执行javascript的监听函数的,例如onload、onerror、onmouseover等等。
CSRF(Cross Site Request Frogy)跨站请求伪造
CSRF攻击与防御:https://blog.csdn.net/xiaoxinshuaiga/article/details/80766369
如何防御
cookies设置sameSite
- 对于CSRF的第二个特点伪造请求的域名不是网站A,那么通过限制cookies不被其他域名网站使用,来达到防御的目的,具体的做法是:
cookies设置sameSite属性的值为strict,这样只有同源网站的请求才会带上cookies。但是此方案有浏览器兼容问题。
验证referer
- 根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地
- 第二个特点同时会造成伪造请求的referer不是网站A,因此我们可以限制不信任的请求来源。具体做法是:
后端可以根据HTTP请求头的`referer`来判断请求是否来自可信任网站。但是这个方案也有局限性,攻击者可以设置
请求不携带referer,所以这个方案适合用于辅助。
验证csrf token
- 这是目前相对成熟的方案之一,具体的做法是:
服务端随机生成token,保存在服务端session中,同时保存到客户端中,客户端发送请求时,把token带到HTTP请求头
或参数中,服务端接收到请求,验证请求中的token与session中的是否一致。
在 HTTP 头中自定义属性并验证
- 这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。