• 作者:老汪软件技巧
  • 发表时间: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,但是大体量的公司,一般可能找运维处理这些问题会比较麻烦,因为可能都不知道运维是谁。

所以,本次低代码搭建的过程,觉得这个思路挺好,以后就能彻底解决跨域问题了,也不用去求别人了。