跨域及解决跨域问题的详细解释

本文介绍了什么是跨域,以及常见的解决跨域的5种方法的具体解释,会举例分别解释每一种方法是怎么使用的。

目录

1.什么是跨域

2.解决跨域问题的方法

(1)JSONP(JSON with Padding)

(2)CORS(Cross-Origin Resource Sharing)

(3)跨文档消息传递(postMessage)

(4)Nginx代理跨域

(5)WebSocket

3.总结


1.什么是跨域

跨域是一个浏览器安全策略,用于防止恶意网站通过 JavaScript 代码访问来自其他网站的资源。同源策略要求网页只能访问与其来源相同的资源,即具有相同的协议(如http或https)、域名和端口号。

例如,假设你的网站位于https://www.example.com,如果你在 JavaScript 中尝试通过XMLHttpRequest请求 https://www.google.com 的数据,这就是一个跨域请求,因为域名不同。

跨域请求默认会被浏览器阻止,因为这可能会导致安全问题。

2.解决跨域问题的方法

(1)JSONP(JSON with Padding)

利用script标签可以跨域请求资源的特性,通过动态创建script标签实现跨域请求。

工作原理如下:

① 前端页面通过动态创建<script>标签,设置src属性为目标服务器API的URL,并同时指定一个回调函数的名称作为URL参数。

function handleResponse(data) {
  // 处理返回的数据
}

let script = document.createElement('script');
script.src = 'http://api.example.com/data?callback=handleResponse';
document.body.appendChild(script);

② 目标服务器收到请求后,将数据封装在回调函数中返回给前端。回调函数的名称由前端传递的callback参数指定。

// 目标服务器处理请求,将数据封装在回调函数中返回
let data = { "name": "John", "age": 25 };
let callbackName = req.query.callback; // 假设通过query参数获取回调函数名称
res.send(callbackName + '(' + JSON.stringify(data) + ')');

③ 前端页面定义回调函数,当服务器返回数据时,会通过回调函数将数据传递给前端,从而实现跨域请求获取数据。

function handleResponse(data) {
  // 处理返回的数据
  console.log(data);
}

 JSONP优势:在于它可以兼容老旧浏览器,并且相对简单易用。

但是需要注意的是,JSONP只支持GET请求,且需要目标服务器的支持,即目标服务器需要事先将数据封装在回调函数中返回给前端。

此外,JSONP存在安全风险,因为它会执行目标服务器返回的任意代码,所以需要确保目标服务器的可信性。最好在使用JSONP时确认目标服务器是否提供了相关支持并了解其安全性。

(2)CORS(Cross-Origin Resource Sharing)

服务器设置响应头中的Access-Control-Allow-Origin字段,指定允许访问的域名,从而允许跨域请求。

假设有一个网页 http://example.com,它试图通过 AJAX 请求从 http://api.lizi.com/data 获取数据,而这两个源(域名)不同,此时就出现了跨域问题。

以下是基于 CORS 的示例:

① 网页 http://example.com 发送 AJAX 请求:

请求地址:http://api.lizi.com/data
请求方法:GET
请求头中的 Origin 字段:http://example.com

② (被访问网址)服务器接收到 AJAX 请求后,返回响应头部信息:

Access-Control-Allow-Origin 字段:指定允许访问该资源的源地址。如果值设为 *,则表示允许任意源的请求访问该资源。必填字段。

Access-Control-Allow-Methods 字段:指定允许的 HTTP 请求方法。可以根据实际需求来设定允许的方法。如果服务器没有设置这个字段,浏览器会默认只允许使用 GET、POST、HEAD 这三个方法进行跨域请求。

Access-Control-Allow-Headers 字段:指定允许的请求头字段,可自定义。

Access-Control-Expose-Headers 字段:指定响应中可以通过响应头访问的额外自定义响应头字段,可自定义。

Access-Control-Max-Age 字段:指定预检请求的缓存时间,即浏览器可以缓存该响应的时间。在指定时间段内,浏览器可以重复使用同样的预检请求结果,而无需再次发送预检请求。

响应头中的 Access-Control-Allow-Origin 字段:http://example.com
响应头中的 Access-Control-Allow-Methods 字段:GET, POST, OPTIONS
响应头中的 Access-Control-Allow-Headers 字段:Content-Type
响应头中的 Access-Control-Expose-Headers 字段:custom-header(自定义)
响应头中的 Access-Control-Max-Age 字段:3600

③ 若服务器允许该跨源请求,浏览器(http://example.com)将接收到实际的响应数据:

响应头中的 Access-Control-Allow-Origin 字段:http://example.com
响应头中的 Access-Control-Expose-Headers 字段:custom-header
响应数据:请求所需的数据。

(3)跨文档消息传递(postMessage)

postMessage 是 JavaScript 浏览器 API 的一部分,是内置在浏览器中的,可以直接在 JavaScript 中使用。postMessage 方法可以在页面的上下文中使用,即在全局 window 对象上调用。通过该方法,可以向其他窗口或文档发送消息,并在目标窗口中接收和处理这些消息。

postMessage 方法的一般语法:

otherWindow.postMessage(message, targetOrigin, [transfer]);
  • otherWindow:目标窗口的引用,可以是通过 window.open 打开的弹出窗口对象、内嵌的 iframe 的 contentWindow、或者通过 window.parent 引用的父窗口对象。
  • message:要发送的消息内容,可以是字符串、数字、布尔值、对象等。
  • targetOrigin:目标文档的源。可以是具体的源,如 'http://example.com',或者通配符 '*' (表示任何源),或者不设置(默认为当前文档的源)。
  • transfer:可选参数,传递的 Transferable 对象(如 ArrayBuffer、MessagePort 等)数组。这些对象将被转移所有权,而不是复制。

示例:

假设有两个页面:

Page A:http://a.example.com/ 和 Page B:http://b.example.com/ ,这两个页面不同源,需要通过 postMessage 进行跨文档通信。

在 Page A 中,使用以下代码向 Page B 发送消息:

const iframe = document.getElementById('iframeB');
const message = { type: 'sendData', data: 'Hello, Page B!' };
const targetOrigin = 'http://b.example.com';
iframe.contentWindow.postMessage(message, targetOrigin);

在 Page B 中,使用以下代码接收来自 Page A 的消息:

window.addEventListener('message', handleMessage);
function handleMessage(event) {
  if (event.origin !== 'http://a.example.com') {
    console.log('Unauthorized origin', event.origin);
    return;
  }

  const message = event.data;
  console.log('Received message', message.type, message.data);

  // 如果是需要的消息类型,则做相应的处理
  if (message.type === 'sendData') {
    handleData(message.data);
  }
}

function handleData(data) {
  console.log('Data from Page A:', data);
}

postMessage 方法仅发送消息,而不提供直接的应答机制。接收方需要通过监听 message 事件,以及在事件处理函数中处理接收到的消息。

(4)Nginx代理跨域

在自己的服务器上设置一个代理,将跨域请求发送到目标服务器,并将响应返回给客户端。

Nginx代理跨域涉及内容较多,会单独写文章来解释。

3.总结

JSONP :

优点是简单易用,兼容性好,并且无需服务端支持,适用于简单的跨域处理。

缺点是只支持 GET 请求,无法处理复杂的跨域场景。

CORS:

优点是简单易用,能够处理复杂的跨域场景,适合做ajax各种跨域请求。

缺点是浏览器IE10以下不支持。

跨文档消息传递(postMessage):

优点是安全可靠,兼容性较好,并且能够处理较为复杂的跨域场景。

缺点是需要浏览器支持 HTML5。

Nginx代理跨域:

部署方便,可以通过简单的配置文件实现跨域处理。Nginx 代理还可以实现请求的负载均衡和缓存等高级功能。

适合前后端分离的前端项目调后端接口。

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值