# 使用 Axios 结合微信安全网关

# 接入指南

  1. 在 HTML 中引入安全网关 Web SDK
<script src="https://web-9gikcbug35bad3a8-1304825656.tcloudbaseapp.com/sdk/2.1.0/cloud.js" importance="VeryHigh"></script>
  1. 新建一个 wxadapter.js 文件,内容如下,修改其中的 GATEWAY_DOMAIN 字段为自己的网关域名,以及 resoureceAppid (填任意一个小程序白名单内的 appid 即可,仅作为来源区分,不校验)
import { AxiosHeaders } from 'axios';
import settle from 'axios/unsafe/core/settle';
import fetchAdapter from 'axios/unsafe/adapters/fetch';
import resolveConfig from 'axios/unsafe/helpers/resolveConfig.js';

const GATEWAY_DOMAIN = 'a2691ef24-wxc0dc4e681cfac36f.sh.wxcloudrun.com' // 网关接入节点域名

const c1 = new window.cloud.Cloud({
  identityless: true,
  resourceAppid: 'wx069a87eae381af2b', // appid,填入接入的小程序 appid
  config: {
    customDomain: `https://${GATEWAY_DOMAIN}`,
  },
});
c1.init(); // 初始化实例

const gateway = c1.services.Gateway({
  domain: GATEWAY_DOMAIN,
}); // 网关接入节点域名,不包含协议头

const wxadapter = (config) =>
  new Promise((resolve, reject) => {
    let { url, ...resolved } = resolveConfig(config)
    gateway
      .call({
        ...resolved,
        path: url,
        header: {
          'X-WX-HTTP-MODE': 'REROUTE',
          ...config.headers,
        },
      })
      .then((result) => {
        const headers = new AxiosHeaders(result.header);
        const response = {
          config,
          data: result.data,
          headers,
          status: result.statusCode,
          statusText: result.errMsg ?? 'OK',
          cookies: result.cookies,
        };
        settle(resolve, reject, response);
      })
      .catch(
        // 降级为普通 fetch 请求
        (error) => {
          console.log(
            error,
            'error when using wx gateway, using fetch adapter to fallback'
          );
          return fetchAdapter(config).then((result) => {
            const response = result;
            settle(resolve, reject, response);
          }).catch(reject);
        }
      );
  });

export default wxadapter;
  1. 在入口 js 处引入上面的 adapter:
import axios from 'axios';
import wxadapter from './wxadapter';
// 应用到默认的 axios 实例
axios.defaults.adapter = wxadapter;
const fallback = false; // 配置是否降级 false 为不降级,失败走降级重试链路,true 为默认降级
// 也可以使用独立的 axios 实例
if(!fallback){
    axios.create({
    // ...config
    adapter: wxadapter
    });
}else{
    axios.create({
    // ...config
    });
}
  1. 测试请求是否正常,以及请求是否通过加密即可。注意 2.0.4 的 SDK 不允许打开 DevTools 调试工具,否则将被拦截。

# FAQ

  1. 降级能力,能否自定义
  • 答:可以通过上面的 wxadapter 的 catch 部分自定义进入降级的条件。
  1. 如何快速关闭
  • 答:步骤 3 入口处取消掉 adapter 的应用即可。
  1. 是否支持服务端主动降级
  • 答:上面代码中,默认任何报错都会进行降级,也可以通过控制台关闭网关的 Web 接入能力强制所有请求降级。
  1. 低版本(0.27.2)Axios 如何使用
import xhrAdapter from 'axios/lib/adapters/xhr';
import settle from 'axios/lib/core/settle';
import buildFullPath from 'axios/lib/core/buildFullPath';
import buildURL from 'axios/lib/helpers/buildURL';

const GATEWAY_DOMAIN = 'a2691ef24-wxc0dc4e681cfac36f.sh.wxcloudrun.com';

const c1 = new window.cloud.Cloud({
  identityless: true,
  resourceAppid: 'wx069a87eae381af2b', // appid,填入接入的小程序 appid
  config: {
    customDomain: `https://${GATEWAY_DOMAIN}`, // 网关接入节点域名
  },
});
c1.init(); // 初始化实例

const gateway = c1.services.Gateway({
  domain: GATEWAY_DOMAIN,
}); // 网关接入节点域名,不包含协议头

const wxadapter = (config) =>
  new Promise((resolve, reject) => {
    var fullPath = buildFullPath(config.baseURL, config.url);
    var url = buildURL(fullPath, config.params, config.paramsSerializer);
    gateway
      .call({
        ...config,
        path: url,
        header: {
          'X-WX-HTTP-MODE': 'REROUTE',
          ...config.headers,
        },
      })
      .then((result) => {
        const headers = result.header;
        const response = {
          config,
          data: result.data,
          headers,
          status: result.statusCode,
          statusText: result.errMsg ?? 'OK',
          cookies: result.cookies,
        };
        settle(resolve, reject, response);
      })
      .catch(
        // 降级为普通 xhr 请求
        (error) => {
          console.log(
            error,
            'error when using wx gateway, using fetch adapter to fallback'
          );
          return xhrAdapter(config).then((result) => {
            const response = result;
            settle(resolve, reject, response);
          });
        }
      );
  });

export default wxadapter;