携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情
什么是跨域
当一个请求的url的协议/端口/域名三者之间任意一个与当前页面的url不同就是跨域
什么是同源策略
同源策略/SOP(same origin pllicy)是浏览器最核心的的安全策略,如果没有同源策略,浏览器很容易受到xss/csfr等攻击,同源策略有效的阻止了非法的跨域之间的数据通讯
同源策略策略是浏览器的安全策略,所有如果通讯不包含浏览器器就没有这个问题。
跨域问题虽然在前端产生,但是前端无法在没有后端支持的情况下解决跨域问题,每个面试官总喜欢问跨域问题,心里真是很郁闷,你能独立解决跨域吗?希望前端面试不要再问这个问题了,建议后端面试时,问一下跨域解决方法,因为在工作中,不止一次遇到跨域问题,大多数的后端都不知道怎么处理,甚至有的要我把允许跨域的响应头发给他,就差替他写了,虽然我也是在面试官频频问的情况下,迫不得已的学习的
html 特殊标签
link script img frame 这些标签具有跨域特性,可以直接访问,不受同源策略策略约束
Jsonp(JSON with Padding) 利用这一点实现的一个跨域,利用script标签发送请求,请求返回一段js代码,就可以在本地执行了。把数据填充到参数中,就可以在客户端函数的参数中获取到数据
举例
服务器端,利用node.js
node.js脚本启动一个服务,监听端口3000,当有人访问http://localhost:3000/jsop 时,返回一个字符串'getJSON({"name":"tom","age":19})',客户端script加载到本地后,就当成json执行,然后本地刚好一个getJOSN函数,就执行这个函数就行了
创建文件 ./server.js ,命令行执行node ./server.js 或者 nodemon ./server.js
const fs = require('fs');
const http = require('http');
const server = http.createServer((req, res) => {
const {
url
} = req;
let data = null;
switch (url) {
case '/data':
// 同步读取data.json内容
data = fs.readFileSync('./data.json')
break;
case "/jsonp":
// 同步读取data.json内容
let json = fs.readFileSync('./data.json')
// 返回数据是一个字符串,js代码 getJSON({"name":"tom","age":19})
data = "getJSON(" + json + ")"
break;
}
res.end(data);
})
server.listen('3000', () => {
console.log('http://localhost:3000')
})
再创建一个data.json文件
{
"name":"tom",
"age":19
}
客户端
首先定义一个函数getJSON(举例叫这个,随便叫),随后在后面利用script向服务器发送一个请求
用live-server打开这个html
http://127.0.0.1:5500/demo1/index.html ,这个路径根据自己真实情况决定,总之和http://localhost:3000/jsop 肯定是不同域
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<!-- jsonp 开始 -->
<script>
function getJSON(res) {
console.log(res);
}
</script>
<script src="http://localhost:3000/jsonp"></script>
<!-- jsonp 结束 -->
</html>
正经的jsonp,不是这种约定函数名的方式实现的,会在url后面拼接?callback=xxx,后端根据这个参数得到函数名,然后返回正确的拼接好的函数调用的字符串,
缺点:只支持get,不支持其他请求方法,不优雅,不正规
CORS
只要服务器端设置 Access-Control-Allow-Origin就可以了,前端无需设置。
现在一般都是用CORS解决跨域,方便快捷,浏览器觉得总有些服务器不怕被攻击,你都不怕,我怕啥,管那个呢,只要你跟我说你来者不惧或者指定的url允许请求你的数据,我就不拦截了
在没解决之前,看看跨域的效果
不解决的效果如下,浏览器控制台中network里面 fetch/Xhr里,状态显示 CORS错误
这个/data ,在开始node.js代码里已经处理了,服务器代码暂时不用改,期望返回一个json,但是实际上服务器也返回了json,但是被浏览器拒绝了。
...
<!-- jsonp 结束 -->
<script>
fetch("http://localhost:3000/data")
.then((response) => response.json())
.then((res) => {
console.log(res);
});
</script>
解决方法
在服务器端配置一下响应头,就ok了,无需前端做任何处理
配置res.setHeader("Access-Control-Allow-Origin", "*"),来者不惧,真的对任何的url都开放,随便调,
配置res.setHeader("Access-Control-Allow-Origin", ['http://127.0.0.1:5500']),只有配置的域名才能访问
...
case '/data':
data = fs.readFileSync('./data.json');
res.setHeader("Access-Control-Allow-Origin", "*")
// 或者
// res.setHeader("Access-Control-Allow-Origin", ['http://127.0.0.1:5500'])
break;
...