前后端分离跨域问题解决

使用前后端分离(前端使用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运行时,显示:

image.png

则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中加入该中间件

image.png

这样就大功告成,如果遇到还有报错,则可以看浏览器的console报错信息,看是否是header的返回字段中缺少什么,再进行相应的添加

参考:
https://learnku.com/articles/6504/laravel-cross-domain-solution
跨域原理解析,讲的挺好的:https://juejin.im/post/5cef28af51882550d41745ea

你可能感兴趣的:(前后端分离跨域问题解决)