所属专题:前端专题导航:HTML、CSS、JavaScript 与 UI 框架

微信小程序开发流程实战:从页面搭建、接口联调到审核发布

微信小程序开发流程实战:从页面搭建、接口联调到审核发布 - 暂无配图,技术文章默认封面

开发一个微信小程序,难点通常不在页面能不能显示,而在页面、后端接口、登录态、隐私说明和正式发布配置能不能一起工作。开发者工具里预览成功,不代表体验版网络配置正确;拿到登录 code,也不代表用户授权了手机号、头像或位置。

本文以原生微信小程序客户端和 Django JSON API 为例,从列表与详情页走完接口约定、登录、隐私、测试和上线。若项目使用 Taro、uni-app 等框架,页面语法不同,但服务端鉴权、域名配置和发布检查仍然适用。通用交付方式可参考软件开发流程实战,网站内容与上线运维见企业网站开发实战;本文聚焦微信小程序特有的工程环节。

一条可复查的开发链路是:拆解页面和数据 → 定义 API → 配置合法域名 → 实现页面状态与服务端登录 → 完成隐私配置和体验测试 → 提交审核并验证正式版。

一、先明确客户端、后端和微信平台的边界

小程序负责交互和展示;自己的后端负责业务校验、数据权限和账号映射;微信平台提供小程序身份及开放能力。客户端代码会随小程序包分发,所以 AppSecret、数据库密码和第三方服务密钥只能放在服务端。

开始前先把用户动作、页面、接口和验收条件对应起来:

用户动作 页面与接口 验收条件
浏览列表 列表页、分页读取接口 加载中、空列表和网络错误都有明确状态
查看详情 详情页、按 ID 读取接口 无效 ID 返回未找到状态,不暴露堆栈
执行登录后操作 登录接口、受保护业务接口 未登录会被拒绝,重复请求不会重复产生副作用

先完成列表和详情,再增加登录或写入操作,可以把页面问题与鉴权问题分开排查。如果首版不需要个人信息,就不要为了演示登录额外收集手机号、头像或位置。

二、创建项目时区分环境

原生小程序通常由 app.json 声明页面,以各页面目录组织 JS、WXML、WXSS 和 JSON 配置。一个小型项目可以按职责组织:

miniprogram/
  app.js
  app.json
  config/
    index.js
  services/
    request.js
    product.js
  pages/
    product-list/
    product-detail/
  components/

目录可以按团队习惯调整,重点是把网络请求和页面展示分开,避免每个页面重复拼接 URL、处理 401 和显示错误。

开发、体验和正式环境应使用各自真实的 API 配置。把 API 基址集中放在配置模块,确认体验版和正式版不会指向开发服务器。配置值必须来自已部署、可访问的 HTTPS 服务;不要把 localhost、临时内网地址或调试开关带入正式包。

还应记录 AppID、环境和基础库版本。AppID 是项目身份配置,AppSecret 是服务端秘密,不能因为 AppID 出现在项目配置里,就把 AppSecret 也放进客户端。

三、先定义 API 契约,再写页面

客户端与服务端先约定稳定的请求和响应结构。列表接口可以返回:

{
  "results": [
    {
      "id": 42,
      "title": "内容标题",
      "summary": "供列表展示的简短摘要",
      "cover_url": null
    }
  ],
  "page": 1,
  "page_size": 20,
  "has_next": false
}

摘要应始终使用约定的纯文本或 HTML 格式;空封面统一为 null;分页明确页码和是否还有下一页。错误响应使用稳定错误码和简短提示,不把 Python 异常、SQL 或服务器路径返回给客户端。

下面的请求层假设 API_BASE 从当前构建环境配置模块导入。正式构建前必须将它设置为当前环境真实的 API 基址:

import { API_BASE } from "../config";

export function request({ path, method = "GET", data }) {
  if (!API_BASE) {
    return Promise.reject(new Error("当前环境未配置 API 地址"));
  }

  const token = wx.getStorageSync("accessToken");
  const header = token
    ? { Authorization: "Bearer " + token }
    : {};

  return new Promise((resolve, reject) => {
    wx.request({
      url: API_BASE + path,
      method,
      data,
      header,
      timeout: 10000,
      success(response) {
        if (response.statusCode >= 200 && response.statusCode < 300) {
          resolve(response.data);
          return;
        }
        const error = new Error("接口返回异常");
        error.statusCode = response.statusCode;
        reject(error);
      },
      fail(error) {
        reject(error);
      }
    });
  });
}

这只是请求封装,不包含重试。只对幂等的读取请求考虑有限重试;创建订单、提交表单等写操作,不能遇到超时就自动重发。服务端可以使用幂等键或业务唯一约束,避免重复记录。

页面应呈现真实加载状态,并分别处理错误和空列表:

import { request } from "../../services/request";

Page({
  data: { items: [], loading: false, error: "" },

  onLoad() {
    this.loadItems();
  },

  async loadItems() {
    this.setData({ loading: true, error: "" });
    try {
      const result = await request({
        path: "/api/mini/v1/products?page=1&page_size=20"
      });
      this.setData({ items: result.results || [] });
    } catch (error) {
      this.setData({
        error: error.statusCode === 401
          ? "登录状态已失效,请重新登录"
          : "暂时无法加载,请检查网络后重试"
      });
    } finally {
      this.setData({ loading: false });
    }
  }
});

有分页时,区分首次加载和追加加载,防止刷新时清空仍可用的内容;连续触发“加载更多”时,也要避免重复请求同一页。服务端分页可参考Django API 分页、缓存与数据库查询优化。

四、合法域名和 HTTPS 要在体验版验证

小程序使用 wx.request、上传或下载文件时,需要在微信公众平台配置对应类型的合法域名。上线前确认:

  • 实际使用到的请求、上传、下载和 WebSocket 域名均已配置;
  • HTTPS 证书有效、域名匹配,接口能从公网访问;
  • DNS、反向代理路径和响应类型在体验版都正确;
  • 体验环境和正式环境配置分离,正式包不会请求开发服务器。

开发者工具的调试设置可能放宽合法域名校验。本地预览成功并不能证明正式版本可请求。排查时先检查当前环境、公众平台合法域名、DNS、TLS 证书和代理路径。小程序网络问题不能只靠网页 CORS 配置解决。

五、登录 code 由服务端兑换

常见登录链路是:客户端调用 wx.login 获取临时 code,把 code 发给自己的后端;后端使用服务器保存的 AppID 和 AppSecret 调用微信 jscode2session,取得当前小程序用户标识;后端完成账号映射后,再签发自己系统的短期会话凭证。

wx.login()
  -> 一次性临时 code
  -> 自己的登录 API
  -> Django 服务端调用 jscode2session
  -> 按 (AppID, OpenID) 查找或创建账号
  -> 签发自己的短期 access token
  -> 客户端后续请求携带 Authorization

code 是临时凭证,只能使用一次。不能重复使用旧 code,也不能从客户端直接调用需要 AppSecret 的服务端接口。OpenID 是用户在特定小程序下的标识,不是密码或授权令牌;不同 AppID 下的 OpenID 不能假设相同。

下面用 Python 标准库展示服务端兑换的核心步骤。配置应从服务器环境或受限配置读取;不要在日志中记录完整请求 URL、AppSecret、code、session_key 或微信响应中的敏感字段。

import json
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode
from urllib.request import urlopen

from django.conf import settings


class MiniProgramLoginError(Exception):
    pass


def exchange_login_code(code):
    if not code:
        raise MiniProgramLoginError("缺少登录凭证")

    params = {
        "appid": settings.WECHAT_MINIAPP_APP_ID,
        "secret": settings.WECHAT_MINIAPP_APP_SECRET,
        "js_code": code,
        "grant_type": "authorization_code",
    }
    endpoint = (
        "https://api.weixin.qq.com/sns/jscode2session?"
        + urlencode(params)
    )

    try:
        with urlopen(endpoint, timeout=5) as response:
            payload = json.loads(response.read().decode("utf-8"))
    except (HTTPError, URLError, TimeoutError) as exc:
        raise MiniProgramLoginError("登录服务暂不可用") from exc
    except (UnicodeDecodeError, json.JSONDecodeError) as exc:
        raise MiniProgramLoginError("登录服务返回了无效响应") from exc

    if not isinstance(payload, dict):
        raise MiniProgramLoginError("登录服务返回了无效响应")
    if payload.get("errcode") != 0 or not payload.get("openid"):
        raise MiniProgramLoginError("登录凭证无效或已过期")

    return payload["openid"], payload.get("session_key")

此函数只应在服务端调用。若业务不需要微信侧数据解密,就不要持久化 session_key;确实需要时也要按最小范围保护。发给客户端的应是本站会话凭证,而不是 session_key。服务端还要校验令牌有效期、用户状态和资源权限;不能只凭客户端提交的 OpenID 判断操作合法。

短期 access token 可以存到小程序本地存储,但必须有过期时间和服务端撤销方式。AppSecret 永远只保存在服务端。登录也不等于用户同意收集手机号、头像或位置,这些能力需要分别设计。

六、把隐私授权放进功能设计

调用个人信息或敏感能力前,先确认功能是否真的需要该数据,并遵循微信当前的用户隐私保护流程:

  1. 列出每类个人信息对应的具体功能和用途;
  2. 在公众平台配置与实际功能一致的隐私保护指引;
  3. 在适当时机说明用途,并按平台要求取得授权;
  4. 用户拒绝时,仍提供不依赖该数据的可用路径;
  5. 后端只保存完成该功能所必需的数据,并按政策处理删除和留存。

不要在启动时一次性请求所有权限,也不要把登录成功表述成用户同意全部隐私条款。页面说明、隐私指引和实际 API 调用必须一致;功能变更后应重新检查。细节以微信官方小程序用户隐私保护指引为准。

七、体验版要覆盖失败路径

场景 应有结果
网络正常 页面内容出现,加载状态按时结束
断网、DNS 失败或接口超时 显示可重试提示,不假装成功
列表为空或详情 ID 无效 显示空状态或未找到状态
token 过期、用户退出 受保护接口返回未授权,客户端重新登录
用户拒绝非必要权限 主要浏览功能仍可使用
连续点击提交或请求超时 不重复创建业务记录
图片失效或字段为空 布局不重叠、不溢出,文字仍能说明内容
正式域名配置错误 在体验阶段发现并修正

另外要在窄屏和较大字体下检查标题、按钮和错误提示,并确认敏感信息没有进入客户端日志。开发者工具可以补充检查,但网络、证书、设备差异和隐私流程仍应使用体验版验证。

八、审核发布后再做线上冒烟测试

正式提交前核对 AppID、环境配置、合法域名、隐私指引、页面入口、图片资源和审核说明。体验版验证后,通过微信公众平台提交审核;审核通过并发布后,用真实账号检查启动、列表、登录和关键业务操作。

后端接口应保持向后兼容。小程序版本发布需要平台流程,遇到客户端问题不一定能立即切回旧版;服务端可通过兼容旧字段、功能开关和分阶段启用,降低新旧客户端并存的风险。发布记录应保存版本号、后端版本、环境配置和降级步骤。审核与自动化发布细节可参考微信小程序 CI 文档。

常见故障排查

现象 优先检查
本地能请求,体验版失败 合法域名、当前环境配置、证书和 DNS
登录偶发失败 code 是否过期或复用、服务端超时和微信错误码
页面一直加载 Promise 成功、失败和结束状态,服务端是否超时
只有正式版请求错误地址 发布包环境配置和公众平台配置是否一致
审核要求补充隐私信息 实际收集字段、隐私指引和授权时机是否一致
服务端返回正常但页面空白 字段名称、分页结构、空值类型和页面条件判断

排障日志保留请求 ID、路径、状态码和耗时即可;不要记录 code、token、AppSecret、手机号等秘密或个人信息。客户端提示应让用户知道下一步,详细堆栈留在受限的服务端日志中。

九、小程序页面不等于公开网页 SEO

小程序是微信平台内的应用。页面能否被微信搜索或其他搜索引擎发现,取决于平台规则、页面开放方式和实际抓取能力;不能把小程序路由直接当成已具备公开网页的 canonical、sitemap 或搜索排名。若文章、产品说明等内容需要参与公开网页搜索,应同时提供可访问、可索引且内容完整的网页,再通过搜索平台验证。

小程序与网站可以共享内容数据,但要分别验证访问入口、权限和索引信号。不要在小程序页面堆关键词,也不要承诺发布后必然收录或排名。站内站内链接审计实战介绍了公开网站的发现路径和内链检查。

发布前检查清单

  • [ ] 页面、API 和验收条件已经对应。
  • [ ] AppSecret 只在服务端配置,没有进入客户端包或日志。
  • [ ] API 基址来自当前构建环境,体验版与正式版分别验证。
  • [ ] 微信公众平台已配置真实 HTTPS 合法域名。
  • [ ] 页面处理了加载、空数据、网络失败、未授权和服务端错误。
  • [ ] 登录 code 由后端兑换,客户端使用本站会话凭证。
  • [ ] 个人信息按功能最小化,并完成隐私说明与授权流程。
  • [ ] 体验版覆盖断网、过期令牌、拒绝授权和重复提交。
  • [ ] 正式发布后完成真实账号冒烟测试,并记录版本与后端配置。

小程序开发流程不止于页面编译成功。把 API 契约、服务端登录、合法域名、隐私边界、体验版失败路径和正式版冒烟测试连成闭环,才能让“能预览”变成“可维护地上线”。示例需要按项目真实的业务模型、API 配置和权限策略调整。

参考资料

分享这篇文章:

评论 (0)

请 登录 后发表评论, 还没有账户?立即注册

暂无评论,快来抢沙发吧!