2

同源和跨域的那些事-简单图文总结 - 安木夕

 1 year ago
source link: https://www.cnblogs.com/anding/p/17459031.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
image.png

01、为什么要跨域?

跨域的根本原因是浏览器的“同源策略”,得先了解什么是同源?—— 就是【协议+域名+端口号】相同,即为同源,只能向同源的服务发起AJAX请求。

151257-20230605214444046-1605751284.jpg
源1 源2 是否同源
a.com b.com 🚫不同源,域名不同
http://a.com https://a.com 🚫不同源,协议不同
a.com:80 a.com:443 🚫不同源,端口不同
gg.com a.gg.com 🚫不同源,子域名不同
a.com/ss a.com/s2 同源

可通过location.originwindow.origin获取当前文档的源

❓为什么要同源呢?

这是浏览器故意设计的,是浏览器的基本安全策略,否则会很容易受到XSS、CSRF攻击。只能向同源的服务发起AJAX请求,不可跨域请求,会被浏览器拦截。

❓有哪些限制规则呢?

  • ✅ 访问其他源的图片、CSS、JS是可以的,允许<img src="url"><link href="url"><script src="url">元素获取的其他源的资源。
  • ✅ Form表单可以跨域提交,表单的提交只是提交数据无需返回,浏览器认为是安全的。
  • 🚫 AJAX不可以向其他源发送网络请求,会被浏览器拦截。注意拦截的不是请求,而是响应,服务端依然是可以收到请求的。
  • 🚫 仅可访问自己域的cookie、localStorage、DOM树,不能访问Iframe嵌入的其他页面内部内容。
image

02、如何实现跨域?

随着互联网越来越复杂,需求也越来越多,跨域请求就很常见了。我们知道了跨域是浏览器的同源限制,就可以针对性的想办法了。

2.1、JSONP跨域

这是一种传统的跨域请求办法,借助于<script>标签元素,因为<script>src可以访问任何站点的资源。当然这需要服务端对应接口支持JSONP(JSON with padding)协议,所以是需要双方约定好,所以浏览器认为这是安全的。

  • 优点是兼任IE,实现跨域。
  • 缺点是不能控制请求过程,仅支持GET方式请求。因为只是一个<script>标签,浏览器自动发起的资源请求。

JSONP(JSON with Padding)是JSON的一种”使用模式“,是一种非官方的协议,用于解决浏览器的跨域数据访问的问题。

📢前端具体实现过程:

  • 1、申明一个全局的回调函数“getData”来接收数据。
  • 2、动态创建一个<script>标签,src为要跨域的API地址,URL中带上回调参数“callback=getData”。
  • 3、服务端收到请求后,动态生成一个脚本,脚本内容是一个字符串,由回调+返回的数据构成:“getData('data')”。
  • 4、本地执行远程脚本,回调函数“getData”运行,就得到了想要的数据。
<script src="http:www.thrid.com/cors/api?q=key&callback=back"></script><script> function back(data) { console.log(data); }</script>

JSONP的实现:

function jsonp(url, args, cbName) { return new Promise((resolve, reject) => { const ele = document.createElement('script'); window[cbName] = (data) => { resolve(data); document.body.removeChild(ele); } args = { ...args, callback: cbName }; ele.src = `${url}?${Object.keys(args).map(k => `${k}=${args[k]}`).join('&')}`; document.body.appendChild(ele); });}//使用,api为360的公开接口jsonp('https://sug.so.360.cn/suggest', { format: 'jsonp', word: 'china' }, 'search') .then(function (data) { console.log(data) });

2.2、CORS跨域

CORS是什么?—— 跨域资源共享 (cross-origin resource sharing),让AJAX可以跨域访问数据。这是为了满足跨域请求的需求,W3C新增加的特性,需要服务端的支持,不支持IE8/9。根据请求方式,浏览器将CORS分为两种情况:

  • 简单请求(安全请求):只支持GET、POST、HEAD,Header只支持部分字段。
  • 复杂请求(其他请求):简单请求以外的其他跨域请求。

🔵简单请求

基本原理就是在请求头加入一个身份来源标识,服务端根据这个标识来判等是否允许访问,如果允许则给一个允许的标记并返回响应。

  • 只支持GET、POST、HEAD。
  • header —— 我们仅能设置基础的安全字段:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type 的值为 application/x-www-form-urlencoded,multipart/form-data 或 text/plain。

📢具体过程比较简单,前端只要在Header加入“Origin”即可:

  • 请求头Header加入要跨域的源:origin:http://www.main.com
GET /api HTTP/1.1Origin: http://www.main.com //本次请求来自哪个源Host: http://www.third.com //请求的第三方APIAccept-Language: en-USConnection: keep-aliveUser-Agent: Mozilla/5.0...
  • 服务端收到请求后检查Origin,如果同意请求则正常响应,同时在响应的Header中加入特殊的“Access-Control-Allow-Origin”字段,申明支持的源,也可以用“*”表示支持任何源访问。
  • 浏览器收到响应后会检查“Access-Control-Allow-Origin”,和当前源对比,如果不合法则会报错——跨域。
Access-Control-Allow-Origin: http://www.main.com //请求允许的源Access-Control-Allow-Credentials: true //是否允许cookie,cors默认不发送cookie,如果要发送,还需AJAX中设置withCredentialsAccess-Control-Expose-Headers: Content-Length,API-Key //如果客户端想要访问其他非安全字段,则需要服务端明确定义哪些Header字段暴露出来Content-Type: text/html; charset=utf-8
image.png

🟠复杂请求

不是简单请求的都称为复杂请求(非简单请求),如请求方法是PUT、DELETE,或Content-Type=application/json。相比于简单请求,复杂请求多了一次预请求。

预请求

  • 正式发送请求前,浏览器会自动发送一个预请求,问问服务端是否允许本次请求,如果回应允许才正式发送请求,后面就和简单请求相同了。
  • 预请求及其响应都没有body,采用OPTIONS方法。
image.png

03、跨域小结

因为同源是浏览器的限制,跨域的方法无非就是绕过,或采用CORS。

跨域方案 基本原理 是否需要服务端支持
JSONP 借助<script>标签的src,加上一个全局回调函数接收数据 🟠需要服务端支持JSONP协议
CORS W3C标准支持的跨域方式,请求头添加Origin字段 🟠需要服务端支持
WebSocket WebSocket可以实现浏览器与服务端的双向通信,没有跨域的困惑。推荐第三方库 Socket.io,可以很方便的建立与服务端的Socket通信。 🟠需要服务端支持,支持WebSocket
iframe+postMessage 使用window.postMessage()来实现窗口之间的通信 🔵不需服务端处理,客户端绕过
服务端代理 由自己的同源服务端代理第三方的请求 🟠需要服务端支持,代理请求
nginx反向代理 原理和服务端代理一样,用nginx配置一个代理服务 🔵不需要服务端修改代码,需nginx支持

©️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址-语雀


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK