什么是跨域?
跨域是指一个域下或者脚本试图去请求另一个域下的资源,这里是跨域的广义的。
广义的跨域:
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地址,也非同源。
同协议:如都是http或者https
同域名:如都是http://luoshushu.com/a和http://luoshushu.com/b
同端口:如都是80端口
如:
http://luoshuhsu.com/a/b.js和http://luoshushu.com/index.php(同源)
不同源栗子
- http://jirengu.com/main.js和 https://jirengu.com/a.php (协议不同)
- http://jirengu.com/main.js和 http://bbs.jirengu.com/a.php (域名不同,域名必须完全相同才可以)
- http://jiengu.com/main.js 和 http://jirengu.com:8080/a.php (端口不同,第一个是80)
同源策略限制以下几种行为:
1、Cookie、LocalStorage 和IndexDB无法读取
2、DOM和js对象无法获得
3、AJAX请求不能发送
常见跨域场景
URL 说明 是否允许通信
http://www.luoshushu.com/a.js
http://www.luoshushu.com/b.js 同一域名,不同文件或路径 允许
http://www.luoshushu.com/lab/c.js
http://www.luoshushu.com:8000/a.js
http://www.luoshushu.com/b.js 同一域名,不同端口 不允许
http://www.luoshushu.com/a.js
https://www.luoshushu.com/b.js 同一域名,不同协议 不允许
http://www.luoshushu.com/a.js
http://192.168.4.12/b.js 域名和域名对应相同ip 不允许
http://www.luoshushu.com/a.js
http://x.luoshushu.com/b.js 主域相同,子域不同 不允许
http://luoshushu.com/c.js
http://www.luoshushu1.com/a.js
http://www.luoshushu2.com/b.js 不同域名 不允许
跨域解决方案
1、
1、通过JSONP跨域
通常为了减轻微博服务器的负载,我们把js、css、img等静态资源分离到另一条独立域名的服务器上,在HTML页面中在通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。
后台server.js栗子
var http = require('http')
var fs = require('fs')
var path = require('path')
var url = require('url')
http.createServer(function(req, res){
var pathObj = url.parse(req.url, true)
switch (pathObj.pathname) {
case '/getNews':
var news = [
"恭喜老铁🎉",
"你拿到数据了",
]
res.setHeader('Content-Type','text/json; charset=utf-8')
if(pathObj.query.callback){
res.end(pathObj.query.callback + '(' + JSON.stringify(news) + ')')
}else{
res.end(JSON.stringify(news))
}
break;
default:
fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){
if(e){
res.writeHead(404, 'not found')
res.end('<h1>404 Not Found</h1>')
}else{
res.end(data)
}
})
}
}).listen(8080)
前端index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
//创建script标签
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参并指定回调执行函数为onBack
script.src = 'http://127.0.0.1:8080/getNews?callback=appendHtml';
document.head.appendChild(script);
// 回调执行函数
function appendHtml(res) {
console.log(JSON.stringify(res));
}
</script>
</body>
</html>
启动终端,在当前文件下执行 node server.js ,浏览器打开 http://localhost:8080/index.html ,查看效果和网络请求
2、跨域资源共享(CORS) 推荐
普通的跨域请求:只要服务器端设置Access-Control-Allow-Origin即可,前端无需设置,若带cookie请求:前后端都要设置。
后台server.js示例:
var http = require('http')
var fs = require('fs')
var path = require('path')
var url = require('url')
http.createServer(function (req, res) {
var pathObj = url.parse(req.url, true)
switch (pathObj.pathname) {
case '/getNews':
var news = [
"你真棒👍",
"数据就这么来了"
]
//后端在响应头上加上Access-Control-Allow-Origin属性
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080')
//所有人都可以访问
//res.setHeader('Access-Control-Allow-Origin','*')
res.end(JSON.stringify(news))
break;
default:
fs.readFile(path.join(__dirname, pathObj.pathname), function (e, data) {
if (e) {
res.writeHead(404, 'not found')
res.end('<h1>404 Not Found</h1>')
} else {
res.end(data)
}
})
}
}).listen(8080)
前端index.html
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<body>
<div class="container">
<ul class="news">
</ul>
<button class="show">点击获取</button>
</div>
<script>
$('.show').addEventListener('click', function () {
var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://127.0.0.1:8080/getNews', true)
xhr.send()
xhr.onload = function () {
appendHtml(JSON.parse(xhr.responseText))
}
})
function appendHtml(news) {
var html = ''
for (var i = 0; i < news.length; i++) {
html += '<li>' + news[i] + '</li>'
}
$('.news').innerHTML = html
}
function $(selector) {
return document.querySelector(selector)
}
</script>
</html>
启动终端,在当前文件下执行 node server.js
,浏览器打开 http://localhost:8080/index.html
,查看效果和网络请求
参考: