本文已参与[新人创作礼]活动, 一起开启掘金创作之路。
场景介绍
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
在1995年,同源策略由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个策略。
所谓同源指的是三个相同:
协议相同。 例如:都是http协议域名相同。 例如:ip地址一样端口相同。 例如:端口号,不能一个8888,一个8080
如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
举个栗子(eg):
意义:同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。同源策略是为了保证用户信息的安全,防止恶意的网站窃取数据。
演示一个跨域的例子
模拟服务端 后台接口
使用http模块快速搭建后台:
var http = require('http')
// 模拟的数据,到时候JSON.stringify数据转换一下返回给客户端
var msg = {
"name" : "狗彬",
"school": "厦门理工学院",
"age" : "23",
"job" : "虚假的vue前端工程师"
}
// 创建服务器
http.createServer( (req, res) =>{
// 解析请求,包括文件名
var ReqPath = req.url;
console.log(ReqPath);
// 编写响应头(不写浏览器不识别)
res.writeHead(200, { 'Content-Type': 'application/json', 'X-Powered-By': 'bacon' });
// 发送响应数据
res.end(JSON.stringify(msg));
}).listen(8888);
// 控制台会输出以下信息
console.log('您的http服务启动在 http://127.0.0.1:8888/');
node 服务端.js
这里我们直接 给它把服务跑起来。注意:我们服务端后台接口的端口号是8888。
试着用8888端口访问,发现一切正常
模拟“客户端”
我们新建一个html文件,作为“客户端”。当然,严格意义来讲,我们这应该属于B/S模式,浏览器/服务器模式。
这里我用<script>标签来引入axios。对,ajax请求我用axios来发起。
同时,我用VScode的open with liveServer插件 模拟网页放在服务器来访问的情景。(网页文件一定要在服务器被请求回来,不然不能发起ajax请求)
来,话不多说,直接上我们“客户端”的代码:
<!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>node 后端接口跨域解决办法</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<input type="button" value="发起请求" onclick="getMsg()">
<p id="Pmsg"></p>
</body>
<script>
function getMsg () {
axios({
method: 'get',//提交方法
url: 'http://127.0.0.1:8888/',//提交地址
}).then((res) => {
// 成功
console.log("成功发起请求,以下是后端接口返回的数据");
console.log(res);
var Pmsg = document.getElementById("Pmsg");
Pmsg.innerHTML = JSON.stringify(res);
}).catch(err => {
// 失败
console.log("请求失败,打印失败信息")
console.log(err);
var Pmsg = document.getElementById("Pmsg");
Pmsg.innerHTML = JSON.stringify(err);
})
}
</script>
</html>
代码写完,直接在VScode右键 选择open with liveServer
可以看到,VScode随机在本机:5500端口给我们打开了网页,由于8888与5500端口不同,所以我们是违反了同源策略的。
多说多嗦无意义,我们直接碰一碰按钮看看反应:
看见了吧,硕大的 has been blocked by CORS policy
这!
就是!!
浏览器跨域!!!
吓不吓人,怕不怕!!!!
别怕,年轻人,有彬哥在,彬哥手把手教你破除
设置响应头
Access to XMLHttpRequest at 'http://127.0.0.1:8888/' from
origin 'http://127.0.0.1:5500' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
仔细分析之前的报错提示,可以看到里面提到的 'Access-Control-Allow-Origin'
这个东西有妙用,具体来说:
Access-Control-Allow-Origin是HTML5中定义的一种解决资源跨域的策略。
通过服务器端返回带有Access-Control-Allow-Origin标识的response header,我们在响应头response里面设置一下,就可以实现跨域访问资源。
设置 'Access-Control-Allow-Origin' 解决跨域
响应头中可以携带一个Access-Control-Allow-Origin字段,其中origin参数的值指定了允许访问该资源的外域URL。
设置只允许来自掘金的请求
// 只允许来自 掘金的请求
res.setHeader('Access-Control-Allow-Origin','https://juejin.cn/')
允许所有域的请求
// 通配符 * 允许来自所有域的请求
res.setHeader('Access-Control-Allow-Origin','*')
虽然允许来自所有域的请求很危险,但是图方便省事的话,确实是个好东西。
具体代码解决之前的demo跨域问题
修改服务端代码:
var http = require('http')
var msg = {
"name" : "狗彬",
"school": "厦门理工学院",
"age" : "23",
"job" : "虚假的vue前端工程师"
}
// 创建服务器
http.createServer( (req, res) =>{
// 解析请求,包括文件名
var ReqPath = req.url;
console.log(ReqPath);
// 通配符 * 允许来自所有域的请求
res.setHeader('Access-Control-Allow-Origin','*')
// 编写响应头(不写浏览器不识别)
res.writeHead(200, { 'Content-Type': 'application/json', 'X-Powered-By': 'bacon' });
// 发送响应数据
res.end(JSON.stringify(msg));
}).listen(8888);
// 控制台会输出以下信息
console.log('您的http服务启动在 http://127.0.0.1:8888/');
运行客户端:
好,非常的ok