解决【跨域问题】它其实so easy

783 阅读4分钟

跨域问题理解

前端跨域处理是解决前端开发过程中由于浏览器的同源策略,而无法直接访问不同源(协议、域名、端口)的资源的问题。

浏览器接收跨域请求时,报错如下: image.png

跨域问题解决

本地配置解决跨域

这些配置均注意在开发和调试环境使用,切勿在生产环境中禁用哦~

绕过浏览器的同源策略

常用调试工具Chrome,支持配置添加--disabel-web-sercurity参数来禁用同源策略。

在Chrome路径后添加--disable-web-security --user-data-dir="自定义目录"(自定义目录,例:d:\ChromeData)

image.png

设置成功后,重新打开Chrome浏览器,都是以禁用浏览器同源策略的方式打开的,并且会带有相关的告警提示:

image.png

巧用浏览器CORS插件

在Chrome应用商店中搜索安装即可。

  • CORS Unblock:解除跨域限制;
  • Allow-Control-Allow-Origin:允许跨域资源共享(CORS);
  • ModHeader:允许用户修改请求头,可以用于测试不同的 CORS 配置;
  • Postman Interceptor:结合 Postman 工具使用,拦截请求和响应,方便测试和调试。

抓包工具代理请求

环境/代码配置解决跨域

1. JSONP

利用<script>标签不受同源策略限制的特点,通过动态插入<script>标签来请求跨域资源。

  • 实现
    • 客户端,创建一个<script>标签,将跨域请求的URL作为src属性。
    • 服务器端:返回的数据需要以函数调用的形式包裹,客户端定义相应的回调函数来接收数据。
  • 缺点:只支持GET请求。
<button id="btn">获取数据</button>
<!-- <script src="http://localhost:3000?cb=callback"></script> -->
<script>
    function jsonp(url, b) {
        return new Promise((resolve, reject) => {
            const script = document.createElement('script');
            script.src = `${url}?cb=${cb}`
            document.body.appendChild(script);
            window[cb] = function(data) {
                resolve(data)
            }
        })
    }
    let btn = document.getElementById('btn');
    btn.addEventListener('click',()=>{
        jsonp('http://localhost:3000','callback')
        .then(res=>{
            console.log('后端响应的数据:',res);
        })
    })
</script>

2. 跨域资源共享(CORS)

通过服务器端设置响应头信息来实现跨域请求。

  • 服务器端
    • Access-Control-Allow-Origin:指定允许跨域请求的源,可以是具体的域名或通配符*
    • Access-Control-Allow-Methods:指定允许使用的请求方法,如GET、POST等;
    • Access-Control-Allow-Headers:指定允许在请求中使用的头部字段;
  • 客户端:浏览器会自动处理;
  • 优点:支持所有类型的HTTP请求,是W3C推荐的标准跨域解决方案。

3. 代理(Proxy)

通过在服务器端设置一个代理服务器,前端与代理服务器通信,代理服务器与目标服务器通信,从而绕过浏览器的同源策略限制。

  • 实现:使用NodeJS的中间件或者Nginx等服务器软件来设置代理
  • 优点:灵活性强,可以配置复杂的路由规则;

例:前端页面部署在:http://10.168.17.122:9887,而后端服务部署在http://10.168.17.122:9888,由于端口不一致,前端请求会跨域,可通过nginx.conf配置,让两者处于同域名和同端口下,配置如下:

server {  
        listen       8080; # 端口  
        server_name  localhost; # 域名  
  
    # 代理所有前端页面  
        location / {  
            proxy_pass http://10.168.17.122:9887;  
        }  
  
    # 代理后端接口  
        location /cors-api {  
            proxy_pass http://10.168.17.122:9888;  
  
      # 添加了部分自定义属性  
            add_header Access-Control-Allow-Origin * always;  
            add_header Access-Control-Allow-Headers *;  
            add_header Access-Control-Allow-Methods "GET, POST, PUT, OPTIONS";  
            if ($request_method = 'OPTIONS') {  
                return 200;  
            }  
        }  
}

4. PostMessage

使用window对象的postMessage方法在不同源的窗口之间发送和接收数据。

  • 实现
    • 发送方:使用postMessage方法发送数据,并指定接收方窗口的引用。
    • 接收方:监听message事件来接收数据。
  • 场景:适用于两个页面之间的跨域通信,如iframe内的页面与父页面之间的通信

5. WebSocket

网络通信协议,可以在单个TCP连接上进行全双工通信。

  • 跨域处理:WebSocket不受同源策略限制,可直接使用;
  • 优点:支持实时通信,适合需要频繁传输数据的应用场景

6. 服务器端反向代理

服务器端设置。

优点:对前端透明,无需修改前端配置;

7. document.domain + iframe

通过设置document.domain属性使不同子域的页面具有相同的域,从而可以相互访问。

场景:适用于主域相同、子域不同的跨域应用场景

8. location.hash + iframe

  • 原理:通过iframelocation.hash来实现跨域通信。
  • 实现步骤:
    • 在一个页面中嵌入一个iframe,并设置其src属性为另一个域的页面。
    • 通过修改iframe的location.hash值来传递数据,监听hashchange事件来接收数据。