什么是跨域访问问题?

跨域访问问题(Cross-Origin Resource Sharing,CORS)是由浏览器的同源策略引起的安全限制。同源策略是一种浏览器安全策略,它要求网页中的所有资源必须来自同一个域名、协议和端口,否则浏览器会阻止跨域的资源请求。
同源策略是浏览器的一种安全机制,它要求以下三项完全相同,才认为两个 URL 属于同源:

  1. 协议(例如:httphttps
  2. 域名(例如:example.comsub.example.com
  3. 端口(例如:804438080

若以上任意一项不同,就被视为跨域

常见的跨域场景

  • 不同域名:如 https://example.comhttps://another.com
  • 不同子域名:如 https://api.example.comhttps://www.example.com
  • 不同端口:如 http://example.com:8080http://example.com:3000
  • 不同协议:如 http://example.comhttps://example.com

如何解决跨域访问问题?

以下是常用的跨域解决方法:

1. CORS (跨域资源共享)

CORS 是服务器端的一种机制,允许客户端访问来自不同源的资源。

  • 服务器设置响应头

    • Access-Control-Allow-Origin:指定允许访问的域名(如 * 或具体域名)。
    • Access-Control-Allow-Methods:指定允许的 HTTP 方法(如 GET, POST)。
    • Access-Control-Allow-Headers:允许的自定义请求头。
    • Access-Control-Allow-Credentials:是否允许发送 cookie
  • 示例(Node.js + Express):

    app.use((req, res, next) => {
        res.setHeader('Access-Control-Allow-Origin', 'https://example.com'); // 允许的源
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST'); // 允许的请求方法
        res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // 允许的请求头
        res.setHeader('Access-Control-Allow-Credentials', 'true'); // 允许 cookie
        next();
    });
    

2. JSONP (JSON with Padding)

JSONP 是一种只支持 GET 请求的跨域解决方法,利用 <script> 标签不受同源策略限制的特性,动态加载资源并执行回调函数。

  • 客户端

    <script src="https://api.example.com/data?callback=myCallback"></script>
    <script>
      function myCallback(data) {
          console.log(data); // 处理返回的数据
      }
    </script>
    

3. 代理服务器

通过设置代理服务器转发请求,使浏览器认为请求是同源的。

  • 示例(Vue 中通过开发服务器代理解决): 在 vue.config.js 中配置:

    module.exports = {
        devServer: {
            proxy: {
                '/api': {
                    target: 'https://api.example.com', // 目标地址
                    changeOrigin: true, // 允许跨域
                    pathRewrite: { '^/api': '' } // 重写路径
                }
            }
        }
    };
    

4. Nginx 反向代理

通过 Nginx 将跨域请求转发到目标服务器。

  • 配置示例

    server {
        listen 80;
        server_name example.com;
    
        location /api/ {
            proxy_pass https://api.example.com/; # 转发请求
            proxy_set_header Host $host;
        }
    }
    

5. 使用 WebSocket

WebSocket 是一种全双工通信协议,不受同源策略限制,适合实时通信的场景。


其他跨域方法和注意点

  1. document.domain
    用于解决同主域不同子域之间的跨域问题,例如:

    • https://api.example.comhttps://www.example.com

    • 前提:需要在页面中将 document.domain 设置为同一个值:

      document.domain = 'example.com';
      
  2. PostMessage
    不同窗口之间可以通过 window.postMessage 方法安全地传递数据。

    • 发送消息

      targetWindow.postMessage(message, targetOrigin);
      
    • 接收消息

      window.addEventListener('message', (event) => {
          if (event.origin === 'https://example.com') {
              console.log(event.data);
          }
      });
      
  3. 跨域脚本引入
    静态资源(如 <script><img><link>)不受同源策略限制,可以直接引入跨域资源。


总结

  • 跨域问题来源:浏览器的同源策略。
  • 二级域名存在跨域问题,但可以通过配置 CORS 或设置 document.domain 解决。
  • 常用解决方案
    1. 服务端设置 CORS(推荐)。
    2. 代理服务器或反向代理。
    3. JSONP(仅支持 GET 请求)。
    4. 使用 WebSocket、PostMessage 或动态脚本加载等方法视场景选择。