【踩坑】Uniapp跨域问题的处理

跨域问题

问题描述

浏览器为了防止跨站请求伪造的攻击，设置了同源策略机制。前端本地开发的 URL 大多是 “http+localhost + 端口”，这会产生跨域、cookie 种植和调用外部服务需要真实域名的问题。

同源策略是指两个源相互之间只有同源，换句话说就是协议、域名和端口都一致，才能相互通信。这样是为了保证请求的安全，减少恶意攻击。

cookie 种植问题-- 如果前后端的鉴权涉及 cookie，那 localhost 之类的域名会影响 cookie 的种植。因为浏览器能否正确种植下 cookie，受到 domain 的影响。

调用外部服务需要真实域名。当我们项目调用外部服务时，经常需要完整的真实域名，比如微信登录。此时本地开发没有完整的真实域名，就无法在本地联调。

为了验证同源，浏览器会在所有请求中附带一个特殊的请求一起发送给域信息接收服务器。服务器返回的 response 会附带一个包含键为Access-Control-Allow-Origin的 header，用来标示什么样的源可以访问服务器的资源。通常分为两种模式，当值为 * 时，服务端允许任何源访问自己的资源。另一种模式则是，指定的源的权限访问。

前端 - 【译】3 种解决 CORS 错误的方式与 Access-Control-Allow-Origin 的作用原理 - 个人文章 - SegmentFault 思否

处理方法

使用扩展插件，关闭浏览器的同源策略检查。插件会在每次请求的 response 中加入一个Access-Control-Allow-Origin:*的 head。但许多时候并不是很管用。

通过代理，作为客户端和服务端之间的中间人，这个代理服务会帮助前端 web app 发送请求，并且接收服务端的返回数据再传送给前端 web app。代理服务在原始的返回中，附加上一个Access-Control-Allow-Origin: * 的header。比如通过 Vue 或 React 等框架来配置 API 代理。本文尝试通过 Vue 建立代理，将本地的数据通过代理端口发出，规避服务器的同源检查策略。Vue 的配置文件（vue.config.js）为：

Copy
module.exports = {
devServer: {
port: 12234,
open: true,
proxy: {
'/api1': { // 拦截以 本地页面地址/api1 发出的请求
target: 'http://......', // 实际的后端地址
changeOrigin: true, // 这里true表示实现跨域
secure: false, // 如果是https接口，需要配置这个参数
pathRewrite: {
'^/api1': '/' // 将/api1重写为 / ; 服务器最终收到的是统一从本地 12234 端口发出的数据
}
},
'/api2': { // 拦截以 本地页面地址/api2 发出的请求
target: 'http://.....', // 另外一个后端地址
changeOrigin: true, // 这里true表示实现跨域
secure: false, // 如果是https接口，需要配置这个参数
pathRewrite: {
'^/api2': '/'
}
}
}
}
};

需要注意的是，Vue 的配置文件需要放在项目文件夹内，与 main.js 同级。

vue：详解 vue 中的代理 proxy_vue proxy-CSDN 博客

什么是跨域 | uni-app 官网 (dcloud.net.cn)

建立自己的代理，同源策略只会作用于浏览器 - 服务之间，而不限制服务 - 服务的通信。

uniapp+uView 实现多个域名或端口的请求

问题描述

在项目代码中，原先是参考Http 请求 | uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架 (uviewui.com)使用 uView 的 http 接口直接对访问的参数和后端地址等的全局设置，并配置为插件在main.js中引入。但当需要访问多个域名或是域名的不同端口时便无法使用这种全局设置。

解决方法

将 uview 的 http 方法在封装一层以设置不同的访问域名或接口。

在配置文件中，写入需要访问的域名或端口。

Copy
baseUrl_a: 'http://...',
baseUrl_b: 'http://...',

在设置 uView http 的全局参数不设置其要访问的 URL。

Copy
uni.$u.http.setConfig((config) => {
// 域名设置
// config.baseURL = projectConfig.baseUrl;
... ...

新建 js 文档，根据不同的域名设置不同的访问方法。

Copy
// requestConfig.js
const http = uni.$u.http;

// 第一类接口的两种方法
export function http_a_get(path,params = ''){

return http.get(projectConfig.baseUrl_a + path, {params});
}

// 第二类接口的两种方法
export function http_b_get(path,params = ''){

return http.get(projectConfig.baseUrl_b + path, {params});
}

在main.js中引入添加到原型。

Copy
import {http_a_get,http_b_get} from '..../reuquestConfig.js';
Vue.prototype.$http_a_get = http_a_get;
Vue.prototype.$http_b_get = http_b_get;

在实际使用中，直接调用封装好的函数。后需要添加新的端口及对应的方法需要在配置文件中添加端口并封装所需要的方法最后在 main.js 中添加到原型。对于原有端口的修改，只需要在 URL 的配置文件中更改即可。

Copy
export function getId(params) {
return http_a_get('/端口后的路径', params);
}