JavaScript同源策略和跨域访问实例详解
什么是JavaScript同源策略
JavaScript同源策略(Same-Origin Policy)是浏览器的一项重要安全限制,它规定了当一个脚本从一个源(域、协议、端口号)加载另一个源的文档时,只能获取同源源的数据,而非其他源的数据。
同源指的是域名、协议、端口三个要素完全相同。当其中至少一个要素不同时,就称两个页面不同源。
为什么要使用同源策略呢?因为如果所有源都能够访问到其他源的数据,恶意攻击者可以轻而易举地盗取用户的敏感信息,这是非常危险的。
如何解决JavaScript跨域问题
虽然JavaScript同源策略可以保护用户的安全,但有时候我们确实需要通过JavaScript获取其他源的数据。那怎么办呢?
主流方式有三种:
1. 使用JSONP
JSONP(JSON with Padding)是一种跨域访问的解决方案,它利用了<script>
标签可以跨域加载资源的特性。
使用JSONP的过程如下:
- 新建一个
<script>
标签,并将它的src
属性设置为要访问的其他源的URL,同时将一个回调函数名作为参数放在URL的末尾,如:
```JavaScript
```
- 然后在文档中定义回调函数
myFunc
,并将数据作为参数传递给它。例如:
JavaScript
function myFunc(data) {
// do something with data
}
- 当浏览器加载这个
<script>
标签时,会执行定义在myFunc
中的回调函数,并将数据作为参数传递给它。这样就完成了从其他源获取数据的过程。
JSONP的缺点在于,它只能用于从其他源获取JSON格式的数据,而且不安全,容易受到XSS攻击。
2. 使用CORS
CORS(Cross-Origin Resource Sharing)是一种跨域访问的官方解决方案,它需要浏览器和服务器同时支持。
使用CORS的过程如下:
- 在服务器的响应头中添加一些特殊的响应头,允许其他源的请求访问本源的资源。例如:
JavaScript
Access-Control-Allow-Origin: http://other-domain.com
- 然后浏览器就可以发送跨域请求,并且在响应中获得数据了。
CORS的优点在于,它可以支持多种数据格式的跨域访问,并且相对JSONP更加安全。
3. 使用代理
使用代理是一种通用的解决方案,可以解决几乎所有的跨域问题。它的原理是在同源的域名下,通过服务器端转发请求来获取目标资源。
使用代理的过程如下:
-
首先在同源的域名下,编写一个服务器端程序(如PHP、Java、Node.js等),接受来自客户端的请求,并将它转发到其他源的URL。
-
客户端发起请求时,将请求发送到同源域名下的服务器上,而不是直接发送到其他源的URL。
-
服务器收到请求后,再将请求转发到其他源的URL,并将返回的数据发送给客户端。
使用代理的优点在于,可以实现几乎所有类型的跨域访问,而且不受同源策略的限制。缺点在于,需要编写服务器端代码,并且服务器的负担较大。
跨域访问实例
下面通过两个例子来说明跨域访问的具体情况和解决方法。
1. 跨域AJAX请求
假设我们的站点是http://example.com
,现在想要向http://other-domain.com/api
发送一个AJAX请求,获取数据并在网页中显示。
直接发送AJAX请求会因为同源策略而失败,会在控制台中报出如下错误:
XMLHttpRequest cannot load http://other-domain.com/api. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://example.com' is therefore not allowed access.
这是因为另一个站点没有在响应中添加CORS头信息导致的。但如果这个站点不是我们自己的,我们又该如何获取数据呢?
解决方案之一是使用代理。在我们自己的服务器上,编写一个中转程序proxy.php
,当客户端向它发送请求时,它将请求转发到其他源的URL,并将返回的数据发送给客户端,如下所示:
<?php
$url = $_GET['url'];
$data = file_get_contents($url);
echo $data;
?>
在客户端的JavaScript代码中,向中转程序proxy.php
发送请求,获取数据,如下所示:
var url = 'http://other-domain.com/api';
var proxyUrl = 'http://example.com/proxy.php?url=' + encodeURIComponent(url);
$.ajax({
url: proxyUrl,
success: function(data) {
// do something with data
}
});
2. 跨域获取JSONP数据
假设我们的站点依然是http://example.com
,现在想要从http://other-domain.com/api
获取JSONP格式的数据。
使用JSONP的方法很简单,只需要在客户端中添加一个<script>
标签,向URL中添加回调函数名参数,并在文档中定义这个回调函数。
下面是一个获取地理位置的JSONP例子:
function displayLocation(data) {
var location = data.city + ', ' + data.region + ', ' + data.country;
$('#location').text(location);
}
var url = 'http://freegeoip.net/json/';
var callbackName = 'displayLocation';
var callbackUrl = 'http://example.com/scripts/' + callbackName + '.js';
$.ajax({
url: url + '?callback=' + callbackName,
dataType: 'jsonp',
jsonpCallback: callbackName,
jsonp: false // don't add '_=timestamp' to URL
});
// in http://example.com/scripts/displayLocation.js
displayLocation({
city: 'Beijing',
region: 'BJ',
country: 'China'
});
在这个例子中,我们向http://freegeoip.net/json/
发送JSONP请求,通过回调函数displayLocation
获取到响应数据。但由于API的限制,请求会报错:
Refused to execute script from 'http://example.com/scripts/displayLocation.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
如果你想在自己的网站中测试JSONP,你可以申请一个开发者账号,或使用一些开放的API。但你要注意安全问题,不要在测试时使用真实的敏感信息。
到这里,你已经掌握了跨域访问的相关知识和解决方法。希望这篇攻略对你有所帮助!
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript同源策略和跨域访问实例详解 - Python技术站