前后端分离项目主流的跨域解决方案

三种主流的跨域解决方案(vue-cli3 package.json中配置跨域)
最近学习nodejs的express框架,对CORS(跨域资源共享Cross-origin resource sharing)比较感兴趣,看过上面的文章后在本地测试发现很多容易忽略的问题导致无法实现跨域,现将解决方案记录如下:

跨域的解决方案:

1.CORS跨域资源共享(后端设置)

弊端:
如果Access-Control-Allow-Origin 设置单一源不能同时设置多个
如果 Access-Control-Allow-Origin 设置为 * 不允许携带 cookie

1.1 使用cors插件处理
1.2 使用自定义中间件设置响应头处理
1.3 使用app.use('*',callback)全局拦截处理响应头

具体实现如下(三个方法选择其一即可):

后端代码实现
服务端node.jssrc/app.js启动文件配置如下:

const express = require('express')
const bodyParser = require('body-parser')//用于解析请求体的中间件,否则无法获取req.body
const app = express()
const models = require('./db/models/index.js')
const baseUrl = '/todo_api'
const cors = require('cors')

//1.cors插件处理跨域
app.use(cors())

//2.自定义中间件处理跨域
/* let allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type, token');
    res.header('Access-Control-Allow-Credentials','true');
    console.log('zqf123')
    next();
};
app.use(allowCrossDomain); */

//3.app.all('*')全局拦截处理跨域
/* app.all('*', (req, res, next)=>{
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type, token');
    res.header('Access-Control-Allow-Credentials',true);
    console.log('res', res)
    next();
}) */

前端代码实现:
在封装的全局拦截请求http.js里设置绝对路径的的baseURL前缀地址,一般为server地址,同时可以根据需要设置header的值。

import axios from 'axios'
// 全局请求头设置
axios.defaults.headers = {
    'Content-Type': 'application/json',
    'token': 'zqf666',
}
//统一设置请求前缀
axios.defaults.baseURL = "http://127.0.0.1:3030/todo_api"

最后将http.js引入到前端项目的入口文件里

//react项目的src/index.js文件
import './http/http.js'

//vue项目的src/main.js文件
import './http/http.js'

容易出现的问题:
由于全局设置了请求头Content-Typetoken,而在node.js里最开始处理CORS时设置为res.header('Access-Control-Allow-Headers', 'Content-Type');导致浏览器控制台报错无法跨域,在postman工具上测试又可以拿到返回的数据,最后用firefox浏览器打开测试了一下虽然还是跨域但是浏览器给出了具体的原因,终于解决。

image.png

2.Http Proxy 代理

弊端:
只能在本地开发使用,线上部署需要搭配Nginx等代理服务器

2.1 在vue项目中使用代理
2.1.1根目录下创建配置文件vue.config.js

module.exports = {
  "lintOnSave": false,//忽略eslint代码检查
    "devServer": {
      "proxy": {
        "/api": {
          "target": "http://127.0.0.1:3030/",//代理的地址
          "changeOrigin": true,
          "ws": true,
          "pathRewrite": {
            "^/api": ""
          }
        }
      }
    }
}

2.1.2不使用vue.config.js配置文件
vue-cli3 中取消了配置文件 vue.config.js,网上的跨域处理多为新建配置文件 vue.config.js,如果不想增加配置文件,则可以在package.json增加配置:

  • package.json 中加入 vue 字段(下面的代码段)
  • 如果请求的地址不是 /api,借助 pathRewrite/api 替换
  • axios 进行网络请求,在封装 axios 时设置 baseURL: '/api'而非绝对路径
"eslintConfig": {
//eslint代码检查规则,代替.eslintrc.js配置文件
},
"vue": {
//代替vue.config.js配置文件
    "lintOnSave": false,//忽略eslint代码检查
    "devServer": {
      "proxy": {
        "/api": {
          "target": "http://127.0.0.1:3030/",//代理的地址
          "changeOrigin": true,
          "ws": true,
          "pathRewrite": {
            "^/api": ""
          }
        }
      }
    }
  }

容易出现的问题:
1.该方法必须在vue-cli3脚手架生成的项目(目录下没有vue.config.js文件)里使用;

  1. package.json的vue字段里设置代理,则vue.config.js文件不能存在,否则package.json的配置会被忽略,如下图:
    image.png

vue-cli3官方文档说明

image.png

2.2 在react项目中使用代理
2.2.1在 package.json 中加入 proxy字段并设置相关代理
image.png

react官方文档说明

官方文档说明

2.2.2在 在config配置文件里设置相关代理
通过create-react-app脚手架安装的react项目只有node_modulespublicsrc文件夹,很多配置文件都没有了,那是因为webpack,babel等都是被creat-react-app封装到了react-scripts这个项目当中,包括基本启动命令都是通过调用react-scripts这个依赖下面的命令进行启动。通过npm run eject将原本creat react appwebpack,babel等相关配置的封装弹射出来,然后就可以在项目的目录下config配置文件,修改代理即可。
image.png

3.使用插件代理

后端实现:
1.安装中间件http-proxy-middleware:
npm i http-proxy-middleware -d
2.在src/app.js中引入中间件并添加配置

// 引用依赖
var express = require('express');
var createProxyMiddleware = require('http-proxy-middleware');
var app = express();
// 创建代理设置中间件选项
var exampleProxy = createProxyMiddleware ( {
        target: 'http://127.0.0.1:3030', // 目标服务器 host
        changeOrigin: true,               // 默认false,是否需要改变原始主机头为目标URL
        ws: true,                         // 是否代理websockets
        pathRewrite: {
            '^/api' : '',     // 重写请求
        },
    };);

// 使用代理
    app.use('/api', exampleProxy);
    app.listen(3000);

请求地址示例:
axios.get(/api/xxx)
前端实现:
axios前缀设置
axios.header.baseURL='/api'

你可能感兴趣的:(前后端分离项目主流的跨域解决方案)