axios跨域请求出现403。
一、nginx代理
一般情况下我们可以通过设置代理来解决跨域问题。给所有异步请求加一个前缀:
比如前端项目部署在8080端口(nginx),后端项目部署在8081端口。
后端提供有两个api:/class/student, /university/college。
前端在访问的时候访问8080端口的/api/class/student, /api/university/college,通过nginx拦截所有以api开头的请求,然后转发给8081端口。这样请求就没有跨域。
但是这样,其他人也可以通过访问8080端口的/api/class/student进而访问到8081端口。
二、跨域
1.前端axios配置
通过如下设置:
axios.defaults.crossDomain = true
//Access-Control-Allow-Origin 指向前端 ip:port
axios.defaults.headers.common['Access-Control-Allow-Origin'] = process.env.VUE_APP_Access_Control_Allow_Origin;
表示所有axios请求都是跨域请求,那么每次请求之前都会发送一个Options(预检)请求,用于询问后端是否允许本次请求。所以需要后端也进行相应的设置。
2.后端配置
后端需要配置一个拦截器,然后给响应添加响应头(包括Access-Control-Allow_Origin[指向前端 ip:port]、Access-Control-Allow-Headers、Access-Control-Allow-Methods)
SpringBoot示例:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Value("${ip-port}")
private String ipPort;
@Override
public void addCorsMappings(CorsRegistry registry) {
//跨域配置 允许所有端口访问
//跨域配置,不可设置为*,不安全, 前后端分离项目,可能域名不一致
//本地测试 端口不一致 也算跨域
registry.addMapping("/**")
.allowedOrigins(ipPort)
.allowedMethods("*")
.allowCredentials(true);
}
}
Node的express框架示例:
const app=require('express')()
app.all("*",function(req,res,next){
//输出请求参数
let data=''
if (req.method==='GET'){
data=JSON.stringify(req.query)
}else {
data=JSON.stringify(req.body)
}
console.log(`${req.path} : ${data}`)
//设置允许跨域的域名,*代表允许任意域名跨域
res.header("Access-Control-Allow-Origin","*");
//允许的header类型
res.header("Access-Control-Allow-Headers","content-type");
//跨域允许的请求方式
res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
// 设置返回数据格式为json
res.header('Content-Type', 'application/json')
if (req.method.toLowerCase() === 'options')
res.send(200); //让options尝试请求快速结束
else
next();
})
注意:当前端需要把cookies也发送出去的时候,需要添加withCredentials。如下对axios进行封装:
const service = axios.create({
// baseURL: '/api',
baseURL: '',
withCredentials: true,
timeout: 10000
})
此时后端也需要对此进行设置(例如SpringBoot中allowCredentials(true)),并且此种情况下响应头的Access-Control-Allow-Origin字段不能为'*'(也要注意慎用localhost)