Appearance
跨域
跨域是指在同一页面中引入来自不同源的资源时,由于浏览器的同源策略,导致无法正常加载资源或访问资源的问题。
常见的跨域场景包括:
- 在 Web 页面中通过 AJAX 请求获取来自不同域的数据;
- 在 Web 页面中通过 iframe 标签引入来自不同域的页面;
- 在 Web 页面中通过 script 标签引入来自不同域的 JavaScript 文件;
同源策略
同源策略(Same-Origin Policy)是浏览器一种安全策略,同源指的是:协议、域名、端口号必须一致。
同源策略限制了一个网页中的 JavaScript 代码只能读取同源网页的数据。如果两个页面的协议、域名或端口有任何一个不同,都被视为不同源,那么就会存在跨域问题。
同源策略是浏览器最基本的安全机制之一,可以防止恶意网站通过 iframe、XHR 等方式窃取用户的信息或者进行 CSRF 攻击等。同时,也为开发者提供了一种简单、可靠的方式来保证自己的 Web 应用程序不受到恶意攻击的威胁。
解决跨域
- JSONP:利用 script 标签可以跨域的特性,将要获取的数据作为参数传递给一个回调函数,服务器将数据作为函数调用的参数返回。缺点是只支持 GET 请求,并且存在安全问题。
- CORS:跨域资源共享是一种标准的跨域解决方案,需要服务器设置相关的响应头,可以支持 GET、POST 等各种类型的请求,并且安全性更高。
- 跨域代理:在同源页面中通过 AJAX 请求获取数据时,可以将请求发送到同源的后端服务器,由后端服务器再将请求发送到目标服务器获取数据,并将数据返回给前端页面。这种方式可以解决跨域问题,但需要部署额外的后端服务。
JSONP (JSON with Padding)
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>JSONP 示例</title>
</head>
<body>
<div id="result"></div>
<script>
function jsonpCallback(data) {
document.getElementById('result').innerHTML = data.name
}
</script>
<script src="https://example.com/api/getUser?callback=jsonpCallback"></script>
</body>
</html>
在这个示例中,页面向 https://example.com/api/getUser 发送了一个跨域请求,并使用名为 jsonpCallback 的回调函数来接收响应数据。当服务器返回数据时,它会使用回调函数名将数据包裹在一个 JavaScript 函数中,例如:
js
jsonpCallback({ name: '张三' })
当客户端代码接收到这个响应时,它会直接调用 jsonpCallback 函数,并将响应数据传递给它。页面中的 result 元素就会显示 "张三"。
JSONP 虽然简单易用,但它有几个明显的缺点:
- 只支持 GET 请求:由于 JSONP 是通过创建一个
<script>
标签来发送请求的,因此它只支持 GET 请求,不能像 AJAX 那样支持 POST、PUT、DELETE 等其他类型的请求。 - 安全风险:JSONP 允许任何服务器返回的 JavaScript 代码在客户端执行,因此存在安全风险。如果不谨慎使用,可能会导致 XSS 攻击等安全问题。
- 缓存问题:由于 JSONP 请求是通过创建一个
<script>
标签来发送的,因此浏览器会缓存请求的结果,这可能会导致无法及时获取最新的数据。
CORS (Cross-Origin Resource Sharing)
CORS (Cross-Origin Resource Sharing) 是一种浏览器安全机制,用于在跨域请求中控制资源的访问权限。
在同源策略的限制下,浏览器只允许在相同域名、协议和端口下进行 HTTP 请求,如果请求的资源不在当前页面所在的域名下,则会被拒绝。而 CORS 允许服务器在响应中设置一些 HTTP 头部信息,告诉浏览器该如何处理跨域请求。通过这些头部信息,服务器可以控制允许哪些域名、协议和端口访问资源,从而解决跨域请求的问题。
在使用 CORS 时,需要在服务器端设置响应头部信息。常见的响应头部信息包括:
- Access-Control-Allow-Origin:指定允许访问资源的域名,可以设置为 "*" 表示允许任何域名访问。
- Access-Control-Allow-Methods:指定允许访问资源的 HTTP 方法,例如 GET、POST、PUT 等。
- Access-Control-Allow-Headers:指定允许访问资源的请求头部信息,例如 Authorization、Content-Type 等。
- Access-Control-Expose-Headers:指定哪些 HTTP 头的名称浏览器能在访问;
- Access-Control-Max-Age:指定预检请求的有效期,即在此时间段内不需要发送预检请求。
通过设置这些头部信息,服务器可以告诉浏览器允许哪些跨域请求,从而保证资源的安全访问。
其中,在进行一些特定类型的跨域请求时,浏览器会在发送真正的请求之前,先发送一个预检请求,用于询问服务器是否支持跨域请求,这个预检请求使用的是 OPTIONS 方法,称为预检请求(Preflight Request)。
预检请求会包含一些额外的头部信息,例如 Origin、Access-Control-Request-Method、Access-Control-Request-Headers 等,用于询问服务器是否支持该跨域请求,并获取一些额外的信息。如果服务器不支持该跨域请求,则会返回一个错误响应,浏览器会根据错误信息进行处理。
- Origin:获取资源的请求是从什么域发起的;
- Access-Control-Request-Headers:用于发起一个预请求,告知服务器正式请求会使用那些 HTTP 头;
- Access-Control-Request-Method:用于发起一个预请求,告知服务器正式请求会使用哪一种 HTTP 请求方法;
代理跨域
代理跨域是一种常见的跨域解决方案,它通过在服务器端设置代理来实现跨域请求。代理跨域的基本思路是,通过服务器端转发请求,将跨域请求转换为同域请求,从而避免了浏览器的跨域限制。
常见代理跨域有:
- 反向代理:反向代理是指代理服务器将请求转发给目标服务器,并将响应返回给客户端。比如:生产当中 Nginx 反向代理。反向代理可以实现负载均衡、安全过滤、静态资源缓存等功能。
- 正向代理:正向代理是指代理服务器将客户端的请求转发给目标服务器,并将响应返回给客户端。比如:开发时 webpack-dev-server 正向代理。 正向代理可以实现隐藏客户端 IP、加速访问速度、访问控制等功能。