更新记录

1.0.3(2026-06-07) 下载此版本

插件id,及插件名更改 由sunrains-utils 变更为sunrains-request


平台兼容性

uni-app(4.0)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
4.61
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟

uni-app x(4.0)

Chrome Safari Android iOS 鸿蒙 微信小程序

sunrains-utils

客户端与服务端之间通信数据加密、签名,保证数据安全与防篡改 支持平台:微信小程序、H5、Android、iOS、鸿蒙 请求方式支持:GET、POST(application/json、application/x-www-form-urlencoded、multipart/form-data(计划中))


模块目录结构

sunrains-utils/
├── index.uts                          # 模块入口,统一导出
├── js_sdk/
│   ├── inutils/
│   │   └── requestApi.uts             # 底层网络请求封装(uni.request / uni.uploadFile)
│   └── openutil/
│       ├── base64Util.uts             # Base64 编解码工具
│       ├── randomUtil.uts             # 随机字符串生成
│       └── request/
│           ├── Request.uts            # 请求入口(ReqApi)
│           └── reqHandle/
│               ├── ReqHandle.uts      # 请求处理抽象基类
│               ├── handle.uts         # 策略工厂(根据 reqFlag 选择 Handler)
│               └── handle/
│                   ├── VoidHandle.uts           # 无加密无签名模式
│                   ├── SignHandle.uts           # 仅签名模式
│                   ├── EncryptHandle.uts        # 仅SM4加密模式
│                   └── SignWithEncryptHandle.uts # 签名+SM4加密模式

导出 API 一览

导出函数 来源文件 说明
ReqApi request/Request.uts 高层请求入口,自动根据 reqFlag 完成签名/加密/发送/解密
RequestApi inutils/requestApi.uts 底层请求入口,直接发起 uni.request 并返回 Promise\<Response>
uploadFile inutils/requestApi.uts 文件上传,返回 Promise\<Response>
stringToBase64 openutil/base64Util.uts 字符串 → Base64 编码
base64ToString openutil/base64Util.uts Base64 → 字符串解码
random openutil/randomUtil.uts 生成指定长度的随机字符串(字母+数字),默认16位

网络请求架构(核心)

整体流程

调用方
  │
  ▼
ReqApi(frontVo: FrontRequestVo)          ← 高层入口
  │
  ├─ 1. selectHandle(reqFlag)            ← 根据模式选择 Handler
  │
  ├─ 2. handle.handleHeaderAndBody(vo)   ← 构造请求头 + 处理请求体(签名/加密)
  │
  ├─ 3. RequestApi(req)                  ← 底层发起 HTTP 请求
  │
  └─ 4. handle.handleRes(req, res)       ← 处理响应(解密/验签)
  │
  ▼
返回 Response

四种请求模式(ReqFlag)

通过 FrontRequestVo.reqFlag 指定,决定请求的安全处理策略:

reqFlag Handler 签名 请求体SM4加密 响应SM4解密 需要priKey 需要pubKey
"void" VoidHandle
"sign" SignHandle ✓ SM2签名
"sm4Encrypt" EncryptHandle ✓ SM4加密 ✓ SM4解密
"signwithenSM2-Sm4Encrypt" SignWithEncryptHandle ✓ SM2签名 ✓ SM4加密 ✓ SM4解密

请求头处理(所有模式共用)

无论哪种模式,handleSignHeader 都会执行以下操作:

  1. SM2加密SM4密钥:生成随机 SM4 key + iv,用服务端公钥(pubKey)通过 SM2 加密后放入 header["key"]
  2. 条件签名(sign / signwithenSM2-Sm4Encrypt 模式):
    • 生成 timestamp(时间戳)和 nonceStr(16位随机串)
    • 将所有业务参数 + timestamp + nonceStr 按 key 字典序排列,拼接为 key=value& 格式
    • 使用客户端私钥(priKey)对拼接字符串进行 SM2 签名
    • 签名结果放入 header["sign"],同时放入 header["timestamp"]header["nonceStr"]

请求体处理(按 HTTP Method + contentType)

GET 请求:

  • void / sign 模式:参数拼接到 URL query string
  • sm4Encrypt / signwithenSM2-Sm4Encrypt 模式:参数 JSON 序列化后 SM4 加密,拼接到 ?data=加密结果

POST 请求(按 contentType):

contentType 处理方式
"json" Content-Type: application/json,加密模式下 body 整体 SM4 加密为 {"data":"加密结果"}
"urlencoded" Content-Type: application/x-www-form-urlencoded,加密模式下 data=加密结果
"form-data" Content-Type: multipart/form-data(暂未实现加密)

响应处理

  • 无加密模式(void / sign):直接返回 Response
  • 加密模式(sm4Encrypt / signwithenSM2-Sm4Encrypt):
    1. 先校验外层 res.code == resSuccessCode()(当前定义为 0
    2. 取出 res.data(SM4 加密的字符串)
    3. 用本次请求生成的 SM4 key + iv 解密
    4. 解密结果为内层 Response,返回给调用方

底层请求(RequestApi)

RequestApi(req: RequestVo) → Promise<Response>
  • 基于 uni.request 封装
  • 超时时间:req.timeout ?? 6000ms
  • 成功(statusCode=200):resolve Response 对象
    • Android 平台特殊处理:通过 JSON.parse(JSON.stringify(res.data)) 转换
    • 其他平台:直接 res.data as Response
  • 失败(非200):reject CustOtherFailError(包含 code + errorMsg)
  • 网络异常:reject CustOtherFailError(包含 errCode + errMsg)

文件上传(uploadFile)

uploadFile(req: UploadFileOptions) → Promise<Response>
  • 基于 uni.uploadFile 封装
  • 超时时间:req.timeout ?? 12000ms
  • 成功时解析 res.data 为 Response
  • 失败时 reject err.errMsg

类型定义(依赖 sunrains-common-type)

FrontRequestVo(前置请求参数)

type FrontRequestVo = {
  method: 'GET' | 'POST',           // HTTP 方法
  url: string,                       // 请求地址
  data: UTSJSONObject | null,        // 请求数据
  header: UTSJSONObject | null,      // 自定义请求头(会与签名/加密头合并)
  reqFlag: ReqFlag,                  // 安全模式标识
  priKey: string,                    // SM2 私钥(签名时使用)
  pubKey: string,                    // SM2 公钥(加密SM4密钥时使用)
  contentType: "json" | "urlencoded" | "form-data" | null,  // POST内容类型
  timeout: number | null,            // 超时时间(ms)
  filePathParamName: string | null   // 上传文件时,文件路径的参数名
}

Response(统一响应)

type Response = {
  success: boolean | null,    // 是否成功
  msg: string | null,         // 提示信息
  code: number,               // 状态码(0=成功)
  errorMsg: string | null,    // 错误详情
  data: any | null            // 业务数据(加密模式下为密文字符串)
}

RequestVo(底层请求参数)

type RequestVo = {
  url: string,
  method?: 'GET' | 'POST' | null,
  header: UTSJSONObject,
  timeout?: number | null,
  data: any
}

Sm4Key(SM4密钥)

type Sm4Key = {
  key: string,
  iv: string
}

错误处理(依赖 sunrains-common-err)

所有请求错误统一通过 UniError 抛出:

错误来源 errSubject errCode message
SM2私钥为空 SM2_PRI_KEY_BLANK 预定义码 预定义信息
SM2公钥为空 SM2_PUB_KEY_BLANK 预定义码 预定义信息
SM2签名失败 SM2_SIGN_FAIL 预定义码 预定义信息
HTTP非200 "请求失败" 服务端code errorMsg / msg
网络异常 "请求失败" err.errCode err.errMsg
加密模式响应码非0 "请求失败" res.code errorMsg / msg

调用方 catch 示例:

try {
  const res = await ReqApi(frontVo)
} catch (err) {
  // 跨平台安全取值(避免 iOS 上 err.message 崩溃)
  console.log("请求异常:", `${err}`)
  // 或通过 err.message 获取错误信息(err 为 UniError 实例)
}

工具函数

Base64 编解码

import { stringToBase64, base64ToString } from "@/uni_modules/sunrains-utils"

const encoded = stringToBase64("Hello")   // "SGVsbG8="
const decoded = base64ToString("SGVsbG8=") // "Hello"

随机字符串

import { random } from "@/uni_modules/sunrains-utils"

const nonce = random(16)   // 生成16位随机字符串

依赖模块

模块 用途
sunrains-smutil SM2签名/加解密、SM4加解密
sunrains-common-type 类型定义(FrontRequestVo、Response、RequestVo、Sm4Key、ReqFlag)
sunrains-common-err 统一错误类(CustFailError、CustOtherFailError)

使用示例

1. 无加密请求(void)

import { ReqApi } from "@/uni_modules/sunrains-utils"

const frontVo: FrontRequestVo = {
  method: "POST",
  url: "http://your-api.com/test",
  data: { name: "张三", age: 18 },
  header: null,
  reqFlag: "void",
  priKey: "",
  pubKey: "",
  contentType: "json",
  timeout: null,
  filePathParamName: null
}
const res = await ReqApi(frontVo)

2. SM2签名请求(sign)

const frontVo: FrontRequestVo = {
  method: "POST",
  url: "http://your-api.com/test",
  data: { name: "张三", age: 18 },
  header: null,
  reqFlag: "sign",
  priKey: "客户端SM2私钥",
  pubKey: "服务端SM2公钥",
  contentType: "json",
  timeout: null,
  filePathParamName: null
}
const res = await ReqApi(frontVo)

3. 签名 + SM4加密请求(signwithenSM2-Sm4Encrypt)

const frontVo: FrontRequestVo = {
  method: "POST",
  url: "http://your-api.com/test",
  data: { name: "张三", age: 18 },
  header: null,
  reqFlag: "signwithenSM2-Sm4Encrypt",
  priKey: "客户端SM2私钥",
  pubKey: "服务端SM2公钥",
  contentType: "json",
  timeout: null,
  filePathParamName: null
}
const res = await ReqApi(frontVo)
// res.data 已自动解密

4. 文件上传(计划中)


隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。