写在前面
跨域概念:跨域是指一个域下的文档或脚本试图去请求另一个域下的资源(比如从a站点获取一个页面,然后在这个页面上去访问b站点的资源,就会发生跨域)
同源:相同协议,相同域名,相同端口
三者相同被称为同源;反之不同源;同源情况下就不存在跨域了。即便两个不同的域名指向同一个ip地址,也非同源。
同源是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击
同源限制
:
1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM 和 Js对象无法获得
3.) AJAX 请求不能发送
备注:浏览器对通过script标签访问其他域名是没有限制的。(比如平时jquery库的引入,就是script标签跨域,但是浏览器没有限制)
// 跨域示例
客户端以XMLHttpRequest对象访问`http://www.tianmao.com`, 天猫返回给客户端,
在`http://www.tianmao.com`域名网页中,有一端js代码请求`http://www.jd.com`,
这时候请求京东网址,会发生跨域,因为浏览器有安全限制,请求发出去,但是数据回不来;
浏览器对XMLHttpRequest对象跨域请求有限制,但是对script标签没有限制
跨域9种解决方案
:
1、 通过jsonp跨域(script标签跨域)
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域(中间server转发)
8、 nodejs中间件代理跨域(中间server转发)
9、 WebSocket协议跨域(新协议不受跨域限制)
跨域鼻祖
最开始针对跨域,需要人为手动修改host。比如当前端本地请求的后端的数据接口是http:api.xx.com/getData
,但是本地浏览器直接访问会跨域;此时可以在本地起一个web服务地址http:127.0.0.1:1111/index.html
,然后修改host文件,使得前端代码中请求api.xx.com
接口时,让请求打到127.0.0.1:1111
服务地址上。这样让本地服务器去访问远程服务器就不会发生跨域,因为跨域不存在后端服务器之间
jsonp
jsonp的底层原理
:通过script标签
发送请求,利用 <script>
标签没有跨域限制的漏洞
jsonp跨域弊端
:
- 只支持
get
请求方式。因为它是使用script标签去发送请求的;而且服务器端需要做处理,客户端也需要做处理;如果跨域时传递的参数非常多,那么这种方式不可取。 - 不安全。server返回的是浏览器直接执行的
func("data")
,不管返回什么,浏览器都会直接执行,如果返回的是木马程序,那。。。。;而且数据是通过url的问号传参的方式,很容易被url劫持。
jsonp优点
: 兼容性好,可用于解决主流浏览器的跨域数据访问的问题
JSONP和AJAX比对:
JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但AJAX属于同源策略,JSONP属于非同源策略(跨域请求)
<!-- 示例1:此时服务器是返回数据了,但是报错语法错误SyntaxError,因为我们是以script的方式请求的,所以服务器返回的数据,客户端就会以js的方式去解析 -->
<script>
document.querySelector('input').onclick = function(){
var script = document.creatElement("script");
script.src = "http://www.jd.com/index.php";
document.body.appendChild(script);
}
</script>
<!-- 示例2:可以将客户端的回调函数作为参数传递给服务器端,让服务器端返回函数调用的字符串形式 -->
<script>
function getInfo(data){
// 处理服务器返回数据
console.log(data);
}
document.querySelector('input').onclick = function(){
var script = document.creatElement("script");
script.src = "http://www.jd.com/index.php?callback=getInfo"; // 需要服务器返回 "getInfo(返回数据)" 这样客户端就可以以js代码解析成函数调用处理
document.body.appendChild(script);
}
</script>
CORS跨域资源共享
普通跨域请求
:只服务端设置Access-Control-Allow-Origin
即可,前端无须设置,若要带cookie请求:前后端都需要设置。
需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。
兼容性
:目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。
CORS跨域原理
:比如客户端在127.0.0.1:5000/index.html
页面访问服务端127.0.0.1:3000
地址,此时发生跨域,服务端可以在响应头中,设置Access-Control-Allow-Origin:127.0.0.1:5000
,允许127.0.0.1:5000
这个地址的客户端访问自己。
注意点:
在cors跨域方式中,客户端会向服务端先进行一次options
试探性请求,服务端看到这个请求,会返回表示同意接下来的跨域请求。
步骤要点
:
1. 客户端(ajax/fetch发送请求)
2. 服务端设置相关头信息(比如允许跨域的域名,允许跨域的方法,允许跨域的cookie凭证)
3. 服务端还需要处理options试探性请求
缺点
:
Access-Control-Allow-Origin
只能设置成* / 一个具体的域名地址,
;如果设置成*
号就不能携带cookie。 因为所有的源都能请求,cookie被传来传去的,浏览器为了保证安全性,所以不允许携带cookie。
http-proxy
一般在webpack、webpack-dev-server中配置; 代理的思想基本都是起一个中间webserver,前端先把请求打到webserver上,然后webserver再请求后端;因为服务到服务之间不存在跨域。
// src/client.js
// 模拟测试client
// 注意这里默认请求的是 http://localhost:8080,但是server.js中启动的是http://localhost:3000,所以跨域了访问不到,
// 提供思路,可以先让client把请求发到webpack的devServe上,devServer是http://localhost:8080服务,然后再让devServer转发到server.js的http://localhost:3000服务上
let xhr = new XMLHttpRequest()
xhr.open('GET', '/api/user', true)
xhr.onload = () => {
console.log(xhr.response);
}
xhr.send()
// src/server.js
let express = require('express')
let app = express()
app.get('/api/user', (req, res) => {
res.send("我是服务端的返回信息hello")
})
app.listen(3000, '127.0.0.1') // 这里的ip可以省略,默认监听的localhost
// webpack.config.js
devServer: {
proxy: {
'/api': 'http://localhost:3000' // 给devServe配置代理,devServer不设置port默认在8080启动,这里表示对http://localhost:8080域名下以/api开头的,会被代理到http://localhost:3000 域名下
}
}
nginx反向代理
比如本地访问后端的地址是www.xxx.com/api
,但是可能会发生跨域,可以在本地搭个nginx
,在nginx中搭个代理服务,然后让本地服务直接请求ng代理服务,然后ng代理服务再把请求转发给远程服务器。
// client.js
正常请求远程服务: www.xxx.com/api
将本地代码请求修改为ng监听地址: `127.0.0.1:80/api`,这样就访问到ng,然后打到 `locaiotn /api/`,ng代理的服务就会去请求`http:www.xxx.com/api`
// 在本地配置nginx.conf
server: {
listen:80
server_name: 127.0.0.1
locaiotn /api/ {
proxy_pass http:www.xxx.com/api
}
}
postMessage
webSocket
juejin.cn/post/684490…
www.ruanyifeng.com/blog/2017/0…
初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处?
答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起,不能从服务端推送数据到客户端;websocket就是一种不仅能从客户端发送数据到服务端,也可以主动从服务的推送数据给客户端的一种全双工通信
协议。
websocket是一种网络通信协议,使用ws://(非加密)和wss://(加密)
作为协议前缀,浏览器对这种通信协议没有跨域限制。
// websocket特点
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
ws://example.com:80/some/path
// client.js
// 执行new WebSocket("wss://echo.websocket.org")就会去连接wss://echo.websocket.org服务器。
var ws = new WebSocket("wss://echo.websocket.org");
// 成功的回调
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!