同源策略是什么?
同源策略是一个浏览器安全机制,它限制了来自不同源(即不同协议、域名或端口号)的脚本如何能够操作彼此的文档,即协议、端口、主机名(域名或IP)完全一致的两个URL(俗称网址)被称为同源。这意味着,一个网页只能操作和访问与其来源相同的文档(包括 iframe 内的文档),不同源的网页,不能共享数据。同源策略的存在可以帮助保护用户的隐私和防止网络攻击。
举例说明:
http://baidu.com //url1
https://baidu.com //url2
http://www.baidu.com //url3
http://localhost:8080 //url4
http://localhost:8080/s //url5
http://localhost:9090 //url6
上面的url2与url1不同源,因为它俩的协议不同;url3与url1也不同源,它俩的域名不一致。
url5与url4是同源的,它俩协议、端口、域名都一致;url6与url4不同源,端口号不一样。
跨域
跨域是指在不同的域名下进行数据请求与访问。由于浏览器同源策略的限制,跨域请求可能会受到阻碍。但有一些方法可以实现跨域请求,我将从CORS、JSONP 和反向代理三个角度说明如何进行跨域。
CORS(跨域资源共享)
CORS是一种跨域资源共享的机制,允许服务器在响应中添加一些HTTP头来告诉浏览器允许跨域访问。
简单请求
简单请求是指满足以下所有条件的请求:
- 请求方法为GET、HEAD或POST
- 请求头部信息不超出以下字段:Accept、Accept-Language、Content-Language、Content-Type(只限于部分值,如text/plain、multipart/form-data、application/x-www-form-urlencoded)
- Content-Type的值仅限于上述三种之一
- 如果请求是使用
XMLHttpRequest对象发出的,在返回的XMLHttpRequest.upload对象属性上没有注册任何事件监听器;也就是说,给定一个XMLHttpRequest实例xhr,没有调用xhr.upload.addEventListener(),以监听该上传请求。 - 请求中没有使用
ReadableStream对象。
对于简单请求,服务器可以在响应中添加Access-Control-Allow-Origin头部信息,指定允许跨域访问的域名或通配符(*),例如:
Access-Control-Allow-Origin: [https://example.com](https://example.com/)
这样,浏览器就会允许来自该域名的网页访问响应中的数据。
复杂请求
对于复杂请求,由于其请求头部信息和请求体较为复杂,服务器需要在响应中添加一组额外的头部信息,以便浏览器确认是否允许跨域访问。这组头部信息包括:
- Access-Control-Allow-Origin:指定允许跨域访问的域名或通配符(*)
- Access-Control-Allow-Methods:指定允许跨域访问的HTTP请求方法
- Access-Control-Allow-Headers:指定允许跨域访问的请求头部信息
- Access-Control-Allow-Credentials:指定是否允许发送Cookie等凭证信息
- Access-Control-Max-Age:指定预检请求的有效期(单位秒)
在处理复杂请求时,服务器需要先响应一个预检请求(OPTIONS请求),以便浏览器确认服务器是否允许跨域访问。预检请求中会带有一些额外的头部信息,如Origin、Access-Control-Request-Method、Access-Control-Request-Headers等,服务器需要根据这些头部信息进行响应。例如:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Origin, Content-Type, Accept
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
这样,浏览器就会允许来自该域名的网页发送请求,并获取响应中的数据。
JSONP(JSON with Padding)
JSONP是一种通过动态创建script标签实现跨域请求的方法,利用浏览器允许跨域加载脚本的特性。
服务器端设置
服务器需要响应一个包含回调函数的JSON数据,例如:
callback({"name":"Jim","age":20});
客户端请求
前端代码需要创建一个新的script标签,并将回调函数作为查询参数传递。例如:
<script>
function callback(data) {
console.log(data);
}
const script = document.createElement('script');
script.src = 'https://example.com/data?callback=callback';
document.body.appendChild(script);
</script>
JSONP缺点
<script>只能发 get 请求- 无法定向分享(可以用 referrer 实现定向)
反向代理
反向代理是指通过代理服务器将客户端请求转发到目标服务器,从而实现跨域请求。这种方法需要配置代理服务器。一般通过 nginx / node.js 配置实现。
服务器端设置
配置代理服务器,例如使用Nginx作为反向代理服务器。在Nginx配置文件中添加以下内容:
location /api/ {
proxy_pass http://target.example.com/;
}
客户端请求
前端代码可以直接发起请求到代理服务器,无需额外设置。
总结
CORS、JSONP 和反向代理都是解决跨域问题的方法。CORS 是现代浏览器推荐的跨域解决方案,JSONP 适用于老版本浏览器,而反向代理允许在服务器端实现跨域请求。根据实际需求和环境选择合适的跨域方法。