跨域(Cross-origin)是 Web 开发中经常会遇到的一种问题,本文将彻底剖析前端开发中跨域问题的各种表现和原因,深入探讨几种跨域解决方案,并提供对应的示例代码。
一、什么是跨域
同源策略(Same-origin policy)是 Web 安全的重要策略之一,它规定了不同源之间的明确分界线,源指的是协议、主机和端口号的组合。
同源策略的实质是一个域下的文档或脚本不能获取另一个域下的内容。但是网络上存在着很多需要进行跨域操作才能正常访问的网页,比如 CDN、第三方登录、跨域 AJAX、IFrame 和跨域资源嵌入等等。
二、跨域表现形式
1. AJAX 跨域:
XMLHttpRequest 和 Fetch 在发起跨域请求时会出现如下异常:
XMLHttpRequest cannot load http://example.com/path. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
2. 动态添加 script 标签跨域:
动态添加的 script 标签可以跨域访问资源,但能获取到的数据受到服务器数据格式及隐私策略的限制,此方法一般用于实现 JSONP 解决跨域问题。
3. 资源跨域嵌入:
在 HTML 代码中,使用跨域资源嵌入(Cross-origin Resource Embedding, CORS)实现跨域,浏览器会发起预检请求(Options),询问服务器是否支持特定的跨域请求,随后发起真正的请求,如果发现请求的资源没有跨域限制,则会正常访问,否则会出现跨域异常。
三、跨域解决方案
1. JSONP
JSONP(JSON with Padding),是通过把 JSON 数据作为参数传递到一个函数中,该函数在回调中处理 JSON 数据。一般来说,JSONP 数据的传输方式是通过 script 标签的 src 属性进行跨域请求,因为 script 标签的跨域限制很少。
服务器返回的数据格式应该是以下的格式:
callbackName({"name": "Lucy", "age": 18})
实现一个简单的 JSONP:
function createJsonp(url, callback) {
const script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', url);
document.body.appendChild(script);
window[callback] = function(data) {
callback(data);
document.body.removeChild(script);
}
}
调用方式:
createJsonp('http://example.com/api?callback=showData', 'showData');
2. CORS
CORS 是解决跨域最常用的解决方案之一,其原理是服务器在响应中添加如下 Header 信息:
Access-Control-Allow-Origin: http://localhost:8000
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin 表示允许访问的来源地址,其取值可以是 *,表示允许来自任何地址的请求。
Access-Control-Allow-Methods 表示允许的 HTTP 请求方法。
Access-Control-Allow-Headers 表示允许的 HTTP 请求头。
Access-Control-Allow-Credentials 表示是否允许携带凭证信息,如 cookie。
客户端的请求代码:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/api', true);
xhr.withCredentials = true; // 携带 cookie
xhr.onload = function() {
console.log(xhr.responseText);
}
xhr.send();
3. postMessage
由于同源策略的限制,在一个页面中嵌入另一个页面无法直接访问并操作另一个页面的 DOM 元素,为了解决这一问题,可以使用 postMessage 来实现跨域通信。
代码示例:
// 主页面:http://localhost:8000/main
window.onload = function() {
const iframe = document.createElement('iframe');
iframe.setAttribute('src', 'http://example.com/iframe.html');
iframe.style.display = 'none';
document.body.appendChild(iframe);
window.addEventListener('message', function(event) {
console.log(event.origin);
console.log(event.data);
});
}
//iframe页面:http://example.com/iframe.html
const targetOrigin = 'http://localhost:8000';
window.parent.postMessage('message from iframe', targetOrigin);
四、总结
跨域问题不是前端开发人员可以绕过的,因为不同的场合会有不同的解决方案,常见的解决方案有 JSONP、CORS 和 postMessage。所以熟悉 Web 安全,了解跨域问题的知识显得至关重要,如果你能够深入理解和掌握跨域问题,相信你在 Web 开发领域的技术影响力也会更大。
本文暂时没有评论,来添加一个吧(●'◡'●)