📄 概述

小程序代码上传服务是一个用于自动化上传小程序代码到微信后台的云服务。通过本服务,开发者可以轻松实现 CI/CD 流程中的代码上传环节。

💡 重要提示

上传接口完全公开,无需登录和 Token 认证,任何用户均可直接调用。

工作流程

💻 开发者
上传代码包
🖥 上传服务
处理请求
📱 微信后台
接收代码

核心特性

特性 说明
✅ 无需认证 上传接口公开访问,无需登录和 Token
✅ 异步处理 基于任务队列,支持高并发上传
✅ 密钥灵活 支持客户端提交密钥或服务器预配置
✅ 版本管理 语义化版本控制,支持版本历史查询

快速开始

POST https://up.umiyun.net/api/v1/upload 🔓 公开接口

使用以下 cURL 命令快速测试上传接口:

bash
curl -X POST https://up.umiyun.net/api/v1/upload \
  -H "Accept: application/json" \
  -F "appid=wx1234567890abcdef" \
  -F "version=1.0.0" \
  -F "description=首次发布版本" \
  -F "codePackage=@/path/to/code.zip" \
  -F "uploadKey=$(cat /path/to/private.key)"

🔧 API 文档

接口信息

项目 说明
接口 URL POST /api/v1/upload
完整地址 https://up.umiyun.net/api/v1/upload
认证方式 无需认证(公开接口)
Content-Type multipart/form-data

请求头说明

请求头 是否必填 说明
Content-Type 必填 必须为 multipart/form-data
Accept 可选 建议设置为 application/json
Authorization 可选 无需设置,该接口为公开接口

📋 请求参数

表单字段

字段名 类型 必填 说明 示例值
appid string 必填 小程序 AppID,以 wx 开头 wx1234567890abcdef
version string 必填 版本号,格式 x.y.z 1.0.0
description string 可选 版本描述信息 修复登录bug
codePackage file 必填 代码包文件(最大 10MB) ZIP 文件
uploadKey string 条件必填 上传密钥(PEM 格式私钥) 见下方说明

参数详细说明

🔐 关于 uploadKey

uploadKey 是小程序代码上传密钥,需要从微信公众平台「开发管理」-「开发设置」中下载。下载后得到一个 .key 文件,文件内容即为 PEM 格式的私钥。

密钥配置方式

🔑 方式一:客户端提交(推荐)

  • 在请求中提供 uploadKey 字段
  • 密钥仅在本次上传中使用
  • 任务完成后立即删除
  • 适用于临时上传、动态密钥场景

💾 方式二:服务器预配置

  • 管理员在服务器配置密钥
  • 无需每次上传时提供
  • 适用于固定密钥场景
  • 需要联系管理员配置
⚠ 密钥优先级

客户端提交 > 服务器预配置。如果两者都未提供,请求将被拒绝。

📥 响应格式

成功响应(HTTP 201)

字段 类型 说明
success boolean 请求是否成功,固定为 true
data.taskId string 任务 ID(UUID 格式)
data.status string 任务状态,初始为 queued
data.createdAt string 任务创建时间(ISO 8601)
json
{
  "success": true,
  "data": {
    "taskId": "550e8400-e29b-41d4-a716-446655440000",
    "status": "queued",
    "createdAt": "2026-01-14T10:00:00.000Z"
  },
  "timestamp": "2026-01-14T10:00:00.000Z"
}

任务状态说明

状态 说明
pending待处理,任务刚创建
queued已加入队列,等待处理
uploading上传中,正在上传到微信后台
success上传成功
failed上传失败
timeout上传超时

错误码

HTTP 状态码

状态码 说明
201创建成功,任务已加入队列
400请求参数错误
404资源不存在
413请求体过大
500服务器内部错误
507存储空间不足

错误码详解

错误码 HTTP 说明 解决方案
MISSING_REQUIRED_FIELDS 400 缺少必填字段 确保包含 appid 和 version
MISSING_CODE_PACKAGE 400 缺少代码包文件 确保包含 codePackage 文件
INVALID_VERSION_FORMAT 400 版本号格式错误 使用 x.y.z 格式
INVALID_UPLOAD_KEY 400 上传密钥格式无效 提供有效的 PEM 格式私钥
MISSING_UPLOAD_KEY 400 未提供上传密钥 提供 uploadKey 或联系管理员
APPID_NOT_FOUND 404 appid 配置不存在 提供 uploadKey 或联系管理员
FILE_TOO_LARGE 413 文件大小超过限制 压缩代码包或联系管理员
INSUFFICIENT_STORAGE 507 存储空间不足 联系管理员清理服务器

📚 使用教程

准备工作

在开始使用上传服务之前,请确保已完成以下准备工作:

1
获取小程序 AppID

登录微信公众平台,在「开发管理」-「开发设置」中找到小程序的 AppID。AppID 以 wx 开头,共 18 位字符。

2
下载上传密钥

在「开发管理」-「开发设置」-「小程序代码上传」中,点击「生成」按钮下载上传密钥。下载后得到一个 .key 文件。

⚠ 安全提示

上传密钥非常重要,请妥善保管,不要泄露给他人。如果密钥泄露,请立即在公众平台重新生成。

3
配置 IP 白名单

在「开发管理」-「开发设置」-「小程序代码上传」中,配置服务器 IP 白名单。如果不配置白名单,上传请求将被微信拒绝。

4
准备代码包

将小程序代码打包为 ZIP 文件。确保 ZIP 文件包含完整的小程序代码,包括 app.jsonapp.js 等必要文件。

上传代码

完成准备工作后,使用以下命令上传代码:

bash
curl -X POST https://up.umiyun.net/api/v1/upload \
  -H "Accept: application/json" \
  -F "appid=你的小程序AppID" \
  -F "version=1.0.0" \
  -F "description=版本描述" \
  -F "codePackage=@/path/to/code.zip" \
  -F "uploadKey=$(cat /path/to/private.key)"

验证上传结果

上传成功后,可以在微信公众平台「版本管理」中查看上传的代码。也可以通过任务查询接口查询上传状态(需要认证)。

💻 代码示例

Node.js
Python
Java
Go
PHP
javascript
const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');

async function uploadCodePackage(appid, version, description, codePackagePath, uploadKey = null) {
  const form = new FormData();
  form.append('appid', appid);
  form.append('version', version);
  form.append('description', description);
  form.append('codePackage', fs.createReadStream(codePackagePath));
  
  if (uploadKey) {
    form.append('uploadKey', uploadKey);
  }

  try {
    const response = await axios.post('https://up.umiyun.net/api/v1/upload', form, {
      headers: {
        ...form.getHeaders(),
        'Accept': 'application/json'
      }
    });
    return response.data;
  } catch (error) {
    if (error.response) {
      throw error.response.data;
    }
    throw error;
  }
}

// 使用示例
(async () => {
  try {
    const result = await uploadCodePackage(
      'wx1234567890abcdef',
      '1.0.0',
      '首次发布版本',
      './code.zip',
      '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----'
    );
    console.log('上传成功:', result);
  } catch (error) {
    console.error('上传失败:', error);
  }
})();
python
import requests

def upload_code_package(appid, version, description, code_package_path, upload_key=None):
    """上传小程序代码包"""
    url = 'https://up.umiyun.net/api/v1/upload'
    
    files = {
        'codePackage': ('code.zip', open(code_package_path, 'rb'), 'application/zip')
    }
    
    data = {
        'appid': appid,
        'version': version,
        'description': description
    }
    
    if upload_key:
        data['uploadKey'] = upload_key
    
    headers = {'Accept': 'application/json'}
    
    try:
        response = requests.post(url, files=files, data=data, headers=headers)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.HTTPError as e:
        return e.response.json()
    finally:
        files['codePackage'][1].close()

# 使用示例
if __name__ == '__main__':
    result = upload_code_package(
        appid='wx1234567890abcdef',
        version='1.0.0',
        description='首次发布版本',
        code_package_path='./code.zip',
        upload_key='-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----'
    )
    print('上传结果:', result)
java
import okhttp3.*;
import java.io.File;
import java.io.IOException;

public class MiniProgramUploader {
    private static final String UPLOAD_URL = "https://up.umiyun.net/api/v1/upload";
    private final OkHttpClient client;

    public MiniProgramUploader() {
        this.client = new OkHttpClient();
    }

    public String uploadCodePackage(String appid, String version, String description, 
                                     String codePackagePath, String uploadKey) throws IOException {
        File codePackage = new File(codePackagePath);
        
        MultipartBody.Builder bodyBuilder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("appid", appid)
                .addFormDataPart("version", version)
                .addFormDataPart("description", description)
                .addFormDataPart("codePackage", "code.zip",
                        RequestBody.create(codePackage, MediaType.parse("application/zip")));
        
        if (uploadKey != null && !uploadKey.isEmpty()) {
            bodyBuilder.addFormDataPart("uploadKey", uploadKey);
        }

        Request request = new Request.Builder()
                .url(UPLOAD_URL)
                .header("Accept", "application/json")
                .post(bodyBuilder.build())
                .build();

        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        }
    }

    public static void main(String[] args) {
        MiniProgramUploader uploader = new MiniProgramUploader();
        try {
            String result = uploader.uploadCodePackage(
                    "wx1234567890abcdef",
                    "1.0.0",
                    "首次发布版本",
                    "./code.zip",
                    "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
            );
            System.out.println("上传结果: " + result);
        } catch (IOException e) {
            System.err.println("上传失败: " + e.getMessage());
        }
    }
}
go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "mime/multipart"
    "net/http"
    "os"
)

func uploadCodePackage(appid, version, description, codePackagePath, uploadKey string) (map[string]interface{}, error) {
    url := "https://up.umiyun.net/api/v1/upload"

    var requestBody bytes.Buffer
    writer := multipart.NewWriter(&requestBody)

    writer.WriteField("appid", appid)
    writer.WriteField("version", version)
    writer.WriteField("description", description)

    file, err := os.Open(codePackagePath)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    part, _ := writer.CreateFormFile("codePackage", "code.zip")
    io.Copy(part, file)

    if uploadKey != "" {
        writer.WriteField("uploadKey", uploadKey)
    }

    writer.Close()

    req, _ := http.NewRequest("POST", url, &requestBody)
    req.Header.Set("Content-Type", writer.FormDataContentType())
    req.Header.Set("Accept", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)

    var result map[string]interface{}
    json.Unmarshal(body, &result)

    return &result, nil
}

func main() {
    result, err := uploadCodePackage(
        "wx1234567890abcdef",
        "1.0.0",
        "首次发布版本",
        "./code.zip",
        "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
    )
    if err != nil {
        fmt.Printf("上传失败: %v\n", err)
        return
    }
    fmt.Printf("上传结果: %v\n", result)
}
php
<?php

function uploadCodePackage($appid, $version, $description, $codePackagePath, $uploadKey = null) {
    $url = 'https://up.umiyun.net/api/v1/upload';
    
    $codePackage = new CURLFile($codePackagePath, 'application/zip', 'code.zip');
    
    $data = [
        'appid' => $appid,
        'version' => $version,
        'description' => $description,
        'codePackage' => $codePackage
    ];
    
    if ($uploadKey !== null) {
        $data['uploadKey'] = $uploadKey;
    }
    
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $data,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => ['Accept: application/json']
    ]);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    $result = json_decode($response, true);
    
    return [
        'success' => $httpCode === 201,
        'data' => $result
    ];
}

// 使用示例
$result = uploadCodePackage(
    'wx1234567890abcdef',
    '1.0.0',
    '首次发布版本',
    './code.zip',
    "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
);

if ($result['success']) {
    echo "上传成功: " . json_encode($result['data']) . "\n";
} else {
    echo "上传失败: " . json_encode($result['data']) . "\n";
}

🔧 故障排除

以下是使用上传服务时可能遇到的常见问题及其解决方案:

MISSING_REQUIRED_FIELDS 缺少必填字段

问题描述:请求中缺少 appid 或 version 字段。

💡 解决方案:
  • 确保请求中包含 appid 字段
  • 确保请求中包含 version 字段
  • 检查字段名是否拼写正确

INVALID_VERSION_FORMAT 版本号格式错误

问题描述:版本号不符合语义化版本格式。

💡 解决方案:
  • 使用 x.y.z 格式,如 1.0.02.1.3
  • 不要使用前导零,如 01.0.0
  • 不要添加额外标签,如 1.0.0-beta

INVALID_UPLOAD_KEY 上传密钥格式无效

问题描述:提供的 uploadKey 不是有效的 PEM 格式私钥。

💡 解决方案:
  • 确保密钥以 -----BEGIN PRIVATE KEY----- 开头
  • 确保密钥以 -----END PRIVATE KEY----- 结尾
  • 检查密钥内容是否完整,没有被截断
  • 如果是通过命令行传递,确保正确转义换行符

FILE_TOO_LARGE 文件大小超过限制

问题描述:上传的代码包文件超过 10MB 限制。

💡 解决方案:
  • 压缩代码包,删除不必要的文件
  • 排除 node_modules、.git 等大型目录
  • 联系管理员调整服务器配置

APPID_NOT_FOUND appid 配置不存在

问题描述:服务器未配置该 appid 的密钥,且请求中未提供 uploadKey。

💡 解决方案:
  • 在请求中提供 uploadKey 字段
  • 或联系管理员在服务器端配置该 appid 的密钥

上传成功但微信后台未显示

问题描述:接口返回成功,但微信公众平台「版本管理」中没有看到代码。

💡 解决方案:
  • 检查服务器 IP 是否已添加到微信公众平台的白名单
  • 确认 uploadKey 是对应小程序的正确密钥
  • 等待几分钟,微信后台可能有延迟
  • 检查任务状态是否为 success

网络连接超时

问题描述:请求上传接口时出现连接超时或网络错误。

💡 解决方案:
  • 检查网络连接是否正常
  • 确认域名 up.umiyun.net 可以正常解析
  • 检查防火墙是否阻止了请求
  • 尝试使用代理或更换网络环境

常见问题

上传接口需要登录吗?

不需要。上传接口完全公开,无需登录和 Token 认证。任何用户均可直接调用该接口上传代码。

uploadKey 是什么?如何获取?

uploadKey 是小程序代码上传密钥,用于授权服务上传代码到微信后台。

获取方式:

  1. 登录微信公众平台
  2. 进入「开发管理」-「开发设置」
  3. 找到「小程序代码上传」部分
  4. 点击「生成」按钮下载密钥文件
上传后如何查看上传结果?

上传成功后会返回 taskId,有以下方式查看结果:

  1. 微信公众平台:登录公众平台,在「版本管理」中查看上传的代码
  2. 任务查询接口:使用 GET /api/v1/tasks/:taskId 查询任务状态(需要认证)
代码包大小限制是多少?

默认限制为 10MB。如果代码包超过此限制,可以:

  • 压缩代码包,删除不必要的文件
  • 排除 node_modules、.git 等大型目录
  • 联系管理员调整服务器配置
版本号格式有什么要求?

版本号必须使用语义化版本格式 x.y.z,其中 x、y、z 均为非负整数。

✅ 有效示例:1.0.02.1.310.20.30

❌ 无效示例:1.0v1.0.01.0.0-beta01.0.0

为什么上传成功但微信后台没有显示?

可能的原因:

  1. IP 白名单未配置:需要在微信公众平台配置服务器 IP 白名单
  2. 密钥不匹配:确认 uploadKey 是对应小程序的正确密钥
  3. 处理延迟:微信后台可能有延迟,请等待几分钟
  4. 任务未完成:检查任务状态是否为 success
如何配置 IP 白名单?
  1. 登录微信公众平台
  2. 进入「开发管理」-「开发设置」
  3. 找到「小程序代码上传」部分
  4. 在「IP白名单」中添加服务器 IP 地址
  5. 保存配置

如果不配置 IP 白名单,微信会拒绝上传请求,导致上传失败。

可以在 CI/CD 中使用吗?

可以。本服务非常适合集成到 CI/CD 流程中:

  • 无需登录认证,直接调用接口
  • 支持命令行工具(如 cURL)调用
  • 提供多种编程语言的 SDK 示例
  • 支持异步处理,适合自动化流程

© 2026 小程序代码上传服务. All rights reserved.

如有问题,请联系技术支持