使用前后端分离(前端使用vue,react应该也类似)的项目都离不开跨域问题,反反复复的经历过好几次后,决定将目前最常用的三种解决方法做下记录,以免后面又在这一部分浪费过多时间。
1、 使用webpack提供的devServer来解决开发环境中跨域问题。这里用vue cli3创建的项目进行说明
注意,这里仅限于开发环境,因为换到线上环境后,我们会对vue项目进行打包,这时候一般使用nginx进行代理,就没有devServer这个环境存在了。
- 打开项目目录下的vue.config.js文件,没有的话,新建一个。配置内容如下。
module.exports = {
devServer: {
host: '0.0.0.0', // 项目运行的IP
port: 8080, // 项目运行的端口
https: false,
// 开发环境跨域使用dev server解决
proxy: {
'/api': { // 匹配到/api的接口请求,我们下面将所有api请求全部加上api标识
target: 'http://api-xxx.xxx.com', // 要转发到的我们的api接口地址
changeOrigin: true,
pathRewrite: {
'^/api': '' // 这里将api这三个字符替换掉,变成我们接口真正的地址
}
}
},
}
}
target:转发的后台api地址
pathRewrite: 地址重写规则
- 在项目目录下新建环境文件.env.development,配置全局变量
VUE_APP_API_BASE_URL = '/api'
这里我们使用axios进行请求,因此,在我们封装的请求文件中设置如下:
axios.defaults.baseURL = process.env.VUE_APP_API_BASE_URL;
这样的话,我们在接口请求中就不用了每个接口都手动加上/api这个标识,axios请求会默认加上该地址。如我们的npm run server运行时,显示:
则axios发出的api请求地址为 http://192.168.123.70:8080/api/接口地址,然后被devServer的进行了代理,将http://192.168.123.70:8080代理到了上面target配置的地址http://api-xxx.xxx.com,且将api替换成了''(这个我们在用浏览器调试的时候是看不到转换过程的,只会看到未转换前的地址),这样就可以不用改变我们的接口请求的代码。
这里有个概念要说一下,上诉代理配置代理的源地址为http://192.168.123.70:8080,如果我们在VUE_APP_API_BASE_URL里写了我们接口的域名前缀,如http://api-xxx.xxx.com/api,则不会被devServer的proxy代理到,导致代理无效。也就是说要从http://192.168.123.70:8080发出去的请求才会被代理到。
2、使用nginx进行代理转发,可在线上环境使用
- 在nginx配置文件(代理vue项目访问地址)中加上:
location /api {
rewrite ^(.*)\/api(.*)$ $1$2;
}
location /api {
add_header 'Access-Control-Allow-Origin' '*';
proxy_pass https://api-xxx.xxx.com;
}
3、在php项目中允许跨域请求(一劳永逸)
- 在请求的入口文件,如index.php里加入如下设置:
header('content-type:application:json;charset=utf8');
// 指定允许其他域名访问
header('Access-Control-Allow-Origin:*');
// 响应类型
header('Access-Control-Allow-Methods:POST, GET, OPTIONS');
// 响应头设置
header('Access-Control-Allow-Headers:authorization,x-requested-with,content-type');
- 使用框架的话,如laravel,可以新建一个中间件
php artisan make:middleware EnableCrossRequest
修改该文件,新建一个handle函数(如果没有),加入:
public function handle($request, Closure $next)
{
$response = $next($request);
$origin = $request->server('HTTP_ORIGIN') ? $request->server('HTTP_ORIGIN') : '';
$allow_origin = [
'http://192.168.123.70:8080',
];
if (in_array($origin, $allow_origin)) {
$response->header('Access-Control-Allow-Origin', $origin);
$response->header('Access-Control-Allow-Headers', 'Origin, Content-Type, Cookie, X-CSRF-TOKEN, Accept, Authorization, authenticated');
$response->header('Access-Control-Expose-Headers', 'Authorization, authenticated');
$response->header('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, OPTIONS');
$response->header('Access-Control-Allow-Credentials', 'true');
}
return $response;
}
然后在Http > Kernel.php中的变量$middleware中加入该中间件
这样就大功告成,如果遇到还有报错,则可以看浏览器的console报错信息,看是否是header的返回字段中缺少什么,再进行相应的添加
参考:
https://learnku.com/articles/6504/laravel-cross-domain-solution
跨域原理解析,讲的挺好的:https://juejin.im/post/5cef28af51882550d41745ea