- 作者:老汪软件技巧
- 发表时间:2024-09-01 11:02
- 浏览量:
背景
最近小伙伴在使用低代码平台marsview搭建页面时,发现一个接口跨域问题。
当在marsview创建的页面里面,配置第三方接口时,由于第三方接口不支持跨域,导致低代码页面请求报错,这个问题怎么处理? 如果不解决,可能用户就无法使用这个平台来搭建页面了。
于是,我思考了一下,跨域虽然有很多方案,但是,由于低代码的特殊性,很多方案是无法使用的,比如:nginx反向代理,后端设置CORS、iframe、JSONP等等。
为什么不能用? 因为低代码配置的第三方接口都是不确定的,你不知道用户会添加什么接口,也就无法再nginx里面做反向代理,同时第三方的接口我们并没有自主权,对方未必会配合我添加CORS,那我该怎么办?
解决方案
既然搭建是基于marsview低代码平台搭建的页面,那问题自然由低代码平台解决,我的方案是开发一个转发接口,由自己的后端去实现接口转发,把参数、请求头等关键信息全部透传过去,毕竟后端调用后端不会出现跨域问题,最终把第三方接口返回的值再返回给低代码平台。
上面是实现功能前,低代码配置的第三方接口跨域报错截图。
前端实现
一、前端配置接口时,开启接口代理。
其他配置方式都不变,只需要开启代理配置即可。
二、修改请求拦截器
// 请求拦截
instance.interceptors.request.use((config) => {
...
config.headers = {
...config.headers,
proxyApi: config.isCors ? config.url : '',
};
// 接口跨域转发
if (config.isCors) {
config.url = `${import.meta.env.VITE_BASE_API}/ai/proxy`;
}
...
return config;
});
这里面有几个关键信息。
前端一共就修改这两处即可,剩下的就交给后端处理。
后端实现
假设你已经会使用Koa开发服务,我们定义一个代理接口,来实现第三方接口转发。
一、简单封装一个request
const { Axios } = require("axios");
/**
* 通用请求类
*/
class Request {
constructor(config) {
this.instance = new Axios({
baseURL: config.baseURL || "",
timeout: 8000,
timeoutErrorMessage: "请求超时",
withCredentials: true,
headers: {
"Content-Type": "application/json",
},
});
}
get(url, params, config = {}) {
return this.instance.get(url, { params, ...config });
}
post(url, params, config = {}) {
return this.instance.post(url, params, config);
}
}
module.exports = new Request({});
封装两个常用的get和post请求,把参数和配置都提前处理好。比如get使用params,post直接传参数,另外增加一个自定义的config以防后期参数扩展。
二、定义服务访问路由
// 接口转发(get)
router.get("/proxy", async (ctx) => {
try {
const {
query,
headers: { host, proxyapi, ...headers },
} = ctx.request;
const response = await request.get(proxyapi, query || {}, {
headers,
});
const res = JSON.parse(response.data);
ctx.body = res;
} catch (error) {
util.fail(ctx, 500, "接口请求失败");
}
});
我们先定义一个get路由,这里有几个关键信息。
三、定义POST请求
为了保证不管是get还是post接口都能实现转发,我们需要复制一个post请求。
// 接口转发(post)
router.post("/proxy", async (ctx) => {
try {
const {
body,
headers: { host, proxyapi, ...headers },
} = ctx.request;
const response = await request.post(proxyapi, JSON.stringify(body || {}), {
headers,
});
const res = JSON.parse(response.data);
ctx.body = res;
} catch (error) {
util.fail(ctx, 500, "接口请求失败");
}
});
跟get基本一样,只是取值有变化,post请求需要从ctx.request.body取值,另外针对参数需要通过JSON.stringify(body || {})转一下。
线上验证
一、拖拽一个按钮,配置一个事件流,调用一个第三方登录接口
二、点击后通过事件流,发送请求
我们会发现,平台发送出去的接口是:/api/ai/proxy,同时在请求头中添加了proxyApi参数,值为第三方接口地址,接口返回了对应的数据。
三、测试post请求
添加第三方post接口地址,开启代理配置。
配置按钮的事件流
点击发送请求测试
我们看到发送了一个post请求出去了,地址是我们开发的后端代理服务。
第三方接口也返回了数据,说明本次低代码平台第三方接口跨域问题解决。
总结
有时候,前端很无奈,跨域其实是一个非常小的问题,惯用的做法就是后端设置一下access-control-allow-origin就可以了,但是由于服务端不愿意加或者服务端统一走的公司网关,自己代码加的不起作用,就需要在网关层加配置,但是网关层可能加起来比较麻烦,最终就不了了之了。
还有一个常用的就是nginx反向代理,小公司可能还好,找运维加一下就OK,但是大体量的公司,一般可能找运维处理这些问题会比较麻烦,因为可能都不知道运维是谁。
所以,本次低代码搭建的过程,觉得这个思路挺好,以后就能彻底解决跨域问题了,也不用去求别人了。