文章目录
前言
总所周知,同源策略是导致跨域的原因,那么什么是同源策略,又可以如何解决跨域的问题呢?咱们一起往下探讨吧~
一、同源策略
-
同源策略/SOP(Same origin policy)是一种约定,由 Netscape 公司 1995 年引入浏览器,它是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。如果缺少了同源策略,浏览器很容易受到 XSS、 CSFR 等攻击。
-
同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个 ip 地址,也非同源。
如下表给出了相对http://
www.example.com/demo/page.html
的同源对比示例:
URL | 是否同源 | 原因 |
---|---|---|
http://www.example.com/demo01/other.html | 是 | 协议、域名、端口相同 |
http://www.example.com/demo/inner/another.html | 是 | 协议、域名、端口相同 |
https:// www.example.com/secure.html | 否 | 协议不同(https ) |
http://www.example.com:81 /demo/etc.html | 否 | 端口 不同 |
http://news.example.com /demo/other.html | 否 | 域名 不同 |
二、跨域
1、 什么是跨域
- 当浏览器中一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。
- 用户在使用浏览器的情况下会使用到 CORS,因为控制访问权限的是浏览器而非服务器。因此使用其它客户端的时候无需关心任何跨域问题。
- 同源策略(Same Origin Policy)是一种约定,它是浏览器最核心也是最基本的安全功能
2、如何解决跨域?
A、代理配置
以/api
为根目录为例
请求跨域接口的时候加上要跨域的接口地址即可
export function signIn() {
return http.get("/api/singIn")
}
①webpack代理配置
具体配置方法参考如下:(可参考devServer.server)
Vue
脚手架创建的项目在vue.config.js
文件配置以下代理(加上logLevel:'debug',
查看代理实际情况)webpack
手动搭建的项目在webpack.config.js
文件配置以下代理(由于不同人搭建方式不一样,如可能在webpack.dev.conf.js
配置,或者对于所抽离的文件)
devServer:{
proxy:{
'/api': {
// 需代理地址
target: 'https://example.com/',
host: '0.0.0.0',
port: port,
// https: true, // 允许https接口代理
// hotOnly: true, // 热更新
// 如果是代理到域名,需要设置changeOrigin: true
changeOrigin: true
// 路径重写(代理重写)
// 如果实际接口没有当前path则需重写路径,且使用调用接口的时候需要加上当前path
// 比如访问的API路径:/api/singIn,设置pathRewrite: {’^/api’ : ‘’},后,最终代理访问的路径:https://example.com/singIn
pathRewrite:{
'^/api':''
}
},
},
}
webpack
低版本代理配置方式
dev:{
proxyTable:{
'/api': {
// 需代理地址
target: 'https://example.com/',
// 如果是代理到域名,需要设置changeOrigin: true
// 路径重写(代理重写)
// 如果实际接口没有当前path则需重写路径,且使用调用接口的时候需要加上当前path
// 比如访问的API路径:/api/singIn,设置pathRewrite: {’^/api’ : ‘’},后,最终代理访问的路径:https://example.com/singIn
pathRewrite:{
'^/api':''
}
},
},
}
②nginx代理配置
下载nginx包
在nginx.conf
文件内配置
location /api {
rewrite ^/api/?(.*)$ /$1 break;
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 允许cros跨域访问
# add_header 'Access-Control-Allow-Origin' '*';
proxy_pass http://0.0.0.0:8080/; # 转发地址
}
B、在服务端设置请求头,一般都是用于项目测试阶段。
- CORS(Cross-Origin Resource Sharing,跨域资源共享)方案
'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie
'Access-Control-Allow-Origin': '*', // 允许访问的域(协议+域名+端口)
'Access-Control-Allow-Methods': "POST,GET,DELETE,PUT,OPTIONS" // 允许请求方式用着五种`
例如:
var http = require('http');
http.createServer(function(request, response) {
response.writeHead(200, {
'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie
'Access-Control-Allow-Origin': '*', // 允许访问的域(协议+域名+端口)(*代表允许全部访问)
'Access-Control-Allow-Methods': "POST,GET,DELETE,PUT,OPTIONS" // 允许请求方式用着五种
})
if (request.url == "/getData") {
const data = {
status: "ok",
data: [{
name: '三妹',
age: 10
}
]
}
response.end(JSON.stringify(data))
}
}).listen(8081,function(){
console.log("服务启动成功");
});
C、JSONP格式
jsonp 是客户端跨源获取服务器数据的通信常用方法。
特点
:简单适用,兼容性好(包括兼容低版本IE
)缺点
:只支持get
请求。核心思想
:网页通过添加< script >
标签,向服务器请求JSON
数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。JSONP
是解决跨域的方法之一,它与AJAX并无任何关联。JSONP
向服务端发送的请求,type
的类型为scrpt
,这与JSONP
的核心思想相对应。AJAX
向服务端发送的请求,它的type类型
为一个xhr对象
,AJAX的源码就是先创建一个xhr的对象,然后发送请求,所以JSONP与AJAX没有任何关系,只是AJAX封装了JSONP。
①原生js使用JSONP
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function getData(data){
document.write(JSON.stringify(data))
}
</script>
<script src="http://localhost:3000/jsonp/jsonp?callback=getData"></script>
</body>
</html>
②jQuery 使用 JSONP
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONP 实例</title>
<script src="https://cdn.static.runoob.com/libs/jquery/1.8.3/jquery.js"></script>
</head>
<body>
<div id="divCustomers"></div>
<script>
// 直接只用$.getJSON调用
$.getJSON("http://localhost:3000/jsonp/jsonp?callback=?", function (data) {
document.write(JSON.stringify(data))
});
// or
// 使用ajax,dataType设置为jsonp调用
$.ajax({
type : "GET",
dataType : "jsonp",
url : "http://localhost:3000/jsonp/jsonp",
success : function(data){
document.write(JSON.stringify(data))
console.log('data', data)
}
})
</script>
</body>
</html>
NodeJs处理接口
使用express构建接口,当然还可以使用express-generator直接生成一个应用程序(推荐使用)
tips:本人使用了express-generator,后续会补充这部分内容
/jsonp/index.js
如下:
var express = require('express');
var router = express.Router();
const url = require("url")
router.get('/test', function (req, res, next) {
res.send('respond with a resource');
});
router.get('/jsonp', function (req, res, next) {
const urlObj = url.parse(req.url,true)
const query = urlObj.query
const data = {
code: 200,
status: "ok",
data: [
{
name: '大三',
age: 10
}
]
}
res.writeHead(200, {
"content-type": "application/json;charset=utf8"
})
let datastr = JSON.stringify(data)
console.log(query.callback)
res.end(query.callback + "(" + datastr + ")")
});
module.exports = router;
注意需使用res.end
返回数据(使用资源进行响应),如果使用res.send
返回会出现以下报错
D、Chrome谷歌浏览器设置“允许跨域”
①修改浏览器设置解决跨域
1、Chrome浏览器地址栏输入“chrome://flags/#block-insecure-private-network-requests”;
2、“Block insecure private network requests”设置为“Disabled”;
3、重启浏览器。
②旧版浏览器修改属性跨域(版本号49之前)
- 右键点击 Chrome 快捷方式图标,点击“属性”。
- 在属性页面中快捷方式栏的目标输入框尾部加上: --disable-web-security
- 点击“应用”和“确定”并关闭属性页面。重新打开 Chrome 浏览器。如果浏览器出现提示“你使用的是不受支持的命令标记 --disable-web-security”,那么说明配置成功,可以跨域访问了。
③新版浏览器修改属性跨域(版本号49之后)
- 在电脑上新建一个目录,例如:C:\ChromeEnvData
- 在属性页面中的目标输入框里加上: --disable-web-security --user-data-dir=C:\ChromeEnvData
- 点击“应用”和“确定”后关闭属性页面,并打开 Chrome 浏览器。发现有“–disable-web-security”相关的提示,说明 Chrome 已经可以正常跨域访问了。
总结
例如:以上就是今天要讲的内容,本文介绍了同源问题及跨域的几个解决方案,欢迎各位大佬阅读,如有错误请提出一起讨论,谢谢!