在今天的内容开始之前需要理解什么是“同源策略”。我不得不拿出 MDN 上的定义:
The same-origin policy is a critical security mechanism that restricts how a document or script loaded from one origin can interact with a resource from another origin. It helps isolate potentially malicious documents, reducing possible attack vectors.
「译」同源策略是一种关键的安全机制,可以限制一个文档或者脚本如何被加载,与其它源的资源如何交互。它有助于隔离潜在的安全文档,减少潜在的攻击载体。
通俗地讲,同源策略是一种「安全机制」,定义了如何加载资源。在浏览器输入一个 URL 后,它会发出一个或者多个 HTTP 请求。下面我写了一个 demo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Load</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
<style>
.bg {
width: 300px;
}
</style>
</head>
<body>
<div id="app">
<p>{{ message }}</p>
<img class="bg" src="http://img4.imgtn.bdimg.com/it/u=2853553659,1775735885&fm=26&gp=0.jpg" alt="" srcset="">
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: '你好前端小课'
}
});
</script>
<script>
$.ajax({
method: "GET",
url: "http://192.168.8.210:9999/api/fe/list",
data: { name: "John", location: "Boston" }
}).done(function (msg) {
alert("Data Saved: " + msg);
});
</script>
</body>
</html>
在Chrome浏览器中加载上面的页面,打开开发者工具可以看到与这个页面相关的所有 HTTP 请求。
总共有 5 个网络请求:
1.webload.html
这个是加载 html 文件需要执行的 HTTP 请求;
2.vue.js
第 8 行代码,使用 script 标签加载 vue.js 文件;
3.jquery.js
第 9 行代码,使用 script 标签加载 jquery.js 文件;
4.u=2853553659,xxxxx
第 20 行代码 img 标签加载的图片;
5.list?name xxxx
第 31 行代码发起的 ajax 请求;
综上,当加载一个页面的时候,与这个页面相关的资源都会通过 HTTP 请求获取。
但是在第 5 个 HTTP 请求的时候,浏览器会报一个错误:
这段代码发起一个 ajax 请求,代码如下:
$.ajax({
method: "GET",
url: "http://192.168.8.210:9999/api/fe/list",
data: { name: "John", location: "Boston" }
}).done(function (msg) {
alert("Data Saved: " + msg);
});
请求地址为:
http://192.168.8.210:9999/api/fe/list
这个请求与我们访问的页面不在同一「源」,违反了浏览器的同源策略,浏览器为安全起见,不会处理返回的响应。http://192.168.8.210:9999 这个是我们前面写的 HTTP 服务器,我拿来用了一下。
我们的主页面地址是:http://192.168.8.210:8080/webload.html,端口为 8080。
同源策略的条件是需要满足协议、host和端口一致,才属于「同源」,举个例子(图来自 MDN):
但是你可能会发现 请求 vue.js 和 jQuery 也不符合同源策略,但为啥能够获取到数据呢?
这是因为 script、img 和 link 标签比较特殊,它不同被同源策略限制。
这种限制虽然可以避免一些安全攻击,但是在实际应用中会经常遇到跨域访问的情况,例如,用户的网站A(www.a.com)后端使用了BOS存储,用户想在该网站的Web应用程序中引用存储在BOS上的资源,但该页面只能请求本域资源,向BOS发送的请求会被浏览器限制,无法直接访问带来不便。为了解决这类跨域访问问题,HTML5提供了一套标准跨域解决方案即CORS(跨域资源共享)。
跨域是突破同源策略的一种手段,有很多种方法可以实现。大的思路是,既然同源策略是浏览器的限制,那么是否可以绕过浏览器的限制呢?
答案是肯定的,比如移动 web 开发中通常会通过 bridge 的方式使用端的网络请求,获取到数据后再把数据交给前端。前端中也可以通过 node 来进行网络请求。或者使用代理的方式。
其实 Server 可以在响应头中设置 Access-Control-Allow-Origin ,这样浏览器就会正常处理接收到的响应,实现跨域。
res.writeHead(200, {
'Access-Control-Allow-Origin': '*'
});
总结
同源策略是浏览器的一种安全手段,不到万不得已的时候能不破坏就不要破坏。实现跨域的手段有很多,大体思想就是想方设法符合同源策略的要求。
推荐阅读:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
https://cloud.baidu.com/doc/BOS/s/djwvys8lg