前端使用Axios时的跨域问题

跨域问题的本质

跨域问题源于浏览器的同源策略(Same-Origin Policy),该策略限制了不同源(协议、域名、端口任一不同)之间的资源交互。Axios作为HTTP客户端,在浏览器环境中受此策略约束。

后端配置CORS

最标准的解决方案是后端配置CORS(跨域资源共享)。以下是Node.js Express框架的示例配置:

const express = require('express');
const cors = require('cors');
const app = express();

// 允许所有来源
app.use(cors());

// 或精细控制
app.use(cors({
  origin: 'https://yourdomain.com',
  methods: ['GET', 'POST'],
  allowedHeaders: ['Content-Type']
}));

对于Spring Boot后端:

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST");
    }
}

前端代理配置

开发环境下可以使用webpack-dev-server或vite的代理功能:

// vite.config.js
export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://backend-server',
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, '')
      }
    }
  }
})

webpack配置示例:

devServer: {
  proxy: {
    '/api': {
      target: 'http://localhost:3000',
      pathRewrite: { '^/api': '' }
    }
  }
}

Axios请求配置

直接请求时可能需要设置withCredentials:

axios.get('https://api.example.com/data', {
  withCredentials: true
})

对于特殊headers的处理:

axios.post('https://api.example.com/login', data, {
  headers: {
    'Content-Type': 'application/json',
    'X-Custom-Header': 'value'
  }
})

JSONP方案(仅限GET)

对于不支持CORS的老旧API,可以使用JSONP:

function jsonp(url, callbackParam, callback) {
  const script = document.createElement('script');
  const callbackName = `jsonp_${Date.now()}`;
  
  url += (url.includes('?') ? '&' : '?') + `${callbackParam}=${callbackName}`;
  script.src = url;
  
  window[callbackName] = data => {
    delete window[callbackName];
    document.body.removeChild(script);
    callback(data);
  };
  
  document.body.appendChild(script);
}

Nginx反向代理

生产环境常用Nginx作为反向代理解决跨域:

server {
    listen 80;
    server_name frontend.com;

    location /api/ {
        proxy_pass http://backend.com/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        add_header 'Access-Control-Allow-Origin' '*';
    }
}

WebSocket跨域处理

WebSocket不受同源策略限制,但可能需要设置协议头:

const socket = new WebSocket('wss://api.example.com/ws');

socket.onopen = () => {
  socket.send(JSON.stringify({action: 'subscribe'}));
};

预检请求处理

对于复杂请求,需要处理OPTIONS预检请求:

// Express中间件示例
app.options('/complex', (req, res) => {
  res.setHeader('Access-Control-Allow-Methods', 'PUT')
     .setHeader('Access-Control-Allow-Headers', 'Content-Type')
     .status(204)
     .end();
});

错误处理示例

Axios跨域请求的典型错误处理:

axios.get('https://external-api.com/data')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    if (error.response) {
      // 服务器响应非2xx
      console.log(error.response.status);
    } else if (error.request) {
      // 请求已发出但无响应
      console.log('No response received');
    } else {
      // 请求配置错误
      console.log('Request setup error', error.message);
    }
  });

每种解决方案都有其适用场景,开发环境推荐使用代理方案,生产环境应优先采用后端CORS配置。JSONP仅作为最后备选方案,因其安全性较差且只支持GET请求。

你可能感兴趣的:(前端)