简介这份资源面向微信小程序开发者与电商、物流场景的技术人员聚焦用户收货地址非结构化、难以统一入库的痛点借助腾讯云地址解析 API 将自由文本自动识别为省、市、区等标准字段实现地址格式化。压缩包共 18 个文件约 16KB以 6 个 js 脚本、5 个 json 配置、3 个 wxss 样式与 2 个 wxml 页面为主另有少量系统隐藏文件整体结构轻量便于直接导入微信开发者工具运行调试。资源已实现 HMAC-SHA1 签名与 Base64 编码等关键环节并保留确认按钮事件待补全读者可据此理解 API 接入、请求构造、JSON 响应解析与异常处理的完整链路。目前已有 8242 人学习下载适合希望快速掌握地址智能识别与标准化落地的初中级开发者参考。1. 地址解析这件小事卡住了多少小程序的转化率用户在小程序里下单收货地址那一栏永远是转化漏斗上最松的一颗螺丝。有人把“广东省深圳市南山区科技园南路 8 号”整段粘进去有人只写“科技园南路8号”还有人把手机号、姓名、地址揉成一坨丢进同一个输入框。后端拿到这串东西省市区字段全是空的运费算不出来电子面单打不出来最后只能靠客服人工拆。这个项目干的就是把这段脏活接过来调用腾讯云地址解析接口把一段自由文本拆成省、市、区、街道、详细地址、姓名、电话再回填成标准结构。适合正在做电商、外卖、寄件类小程序又不想自己维护一套地址词典和正则库的开发者。整套东西是一个可运行的测试工程压缩包解压后直接能看到调用链路改个密钥就能跑。2. 工程结构与调用链路从一段文本到结构化字段2.1 目录里都有什么解压后是一个典型的微信小程序工程骨架没有花哨的构建工具用微信开发者工具直接导入根目录即可。核心文件分布大致如下路径作用app.js/app.json小程序入口与全局配置声明页面路由pages/index/index.js主页面逻辑负责收集输入、触发解析、渲染结果pages/index/index.wxml输入框、解析按钮、结果卡片的视图层utils/addressParse.js地址解析的封装层统一处理请求与返回config/tencent.js密钥与接口地址配置实际项目里应替换为服务端下发project.config.json开发者工具项目配置含 appid 占位这个分层很朴素但边界是清楚的页面只管交互utils只管协议config只管凭据。二次开发时最常动的就是utils/addressParse.js和config/tencent.js两个文件其余基本不用碰。2.2 一次解析请求的完整链路用户在输入框粘贴一段文本点“解析”页面把文本交给封装层封装层拼装请求参数、计算签名、发起 HTTPS 请求拿到 JSON 后做字段归一化再回传给页面渲染。整条链路里最容易翻车的是签名环节腾讯云 API 3.0 的签名要求对请求头、请求体做多轮哈希顺序错一步就返回鉴权失败。常见做法是把签名逻辑单独抽一个函数输入是密钥、时间戳、请求体输出是Authorization头。下面这段是封装层里签名与请求的核心骨架语言为 JavaScript运行在小程序环境// utils/addressParse.js const crypto require(./sha256.min.js); // 小程序无 Node crypto需引入纯 JS 实现 // 腾讯云 API 3.0 签名对 canonicalRequest 做多轮 HMAC-SHA256 function buildAuthorization(secretId, secretKey, payload, timestamp) { const service ocr; const host ocr.tencentcloudapi.com; const date new Date(timestamp * 1000).toISOString().slice(0, 10); // 第一步拼规范请求串注意 HTTP 方法、URI、查询串、头部、签名头都要小写并排序 const canonicalHeaders content-type:application/json\nhost:${host}\n; const signedHeaders content-type;host; const hashedPayload crypto.sha256(payload); const canonicalRequest [ POST, /, , canonicalHeaders, signedHeaders, hashedPayload ].join(\n); // 第二步拼待签字符串算法、日期、服务、终态哈希缺一不可 const credentialScope ${date}/${service}/tc3_request; const stringToSign [ TC3-HMAC-SHA256, timestamp, credentialScope, crypto.sha256(canonicalRequest) ].join(\n); // 第三步逐级派生签名密钥日期 - 服务 - 终态顺序不能换 const kDate crypto.hmacSha256(TC3${secretKey}, date); const kService crypto.hmacSha256(kDate, service); const kSigning crypto.hmacSha256(kService, tc3_request); const signature crypto.hmacSha256(kSigning, stringToSign); return TC3-HMAC-SHA256 Credential${secretId}/${credentialScope}, SignedHeaders${signedHeaders}, Signature${signature}; } // 对外暴露的解析函数输入自由文本输出标准化地址对象 function parseAddress(rawText) { const payload JSON.stringify({ ImageBase64: , Text: rawText }); const timestamp Math.floor(Date.now() / 1000); const authorization buildAuthorization( config.secretId, config.secretKey, payload, timestamp ); return new Promise((resolve, reject) { wx.request({ url: https://ocr.tencentcloudapi.com, method: POST, header: { Content-Type: application/json, X-TC-Action: ParseAddress, // 地址解析的具体 Action X-TC-Version: 2018-11-19, // 接口版本写错会报 Action 不存在 X-TC-Timestamp: timestamp, Authorization: authorization }, data: payload, success: (res) resolve(normalize(res.data.Response)), fail: reject }); }); }这段代码有三个参数值得盯住。X-TC-Action决定调哪个能力地址解析对应ParseAddress写错成别的名字接口会直接告诉你 Action 不存在。X-TC-Version是接口版本号不同版本字段结构可能不同别随手改。timestamp必须用秒级时间戳且与服务端时间偏差不能超过五分钟手机时间不准就会鉴权失败这是最常见的“玄学”问题之一。2.3 返回字段的归一化接口返回的Response里通常带AddressInfos数组每个元素含Province、City、District、Street、DetailAddress、Name、Phone等字段。原始返回不一定每个字段都有值归一化层要做的是补默认值、去空白、把“省/市/区”后缀统一。下面这段是归一化函数// 把接口原始返回整理成页面可直接绑定的结构 function normalize(response) { if (!response || !response.AddressInfos || !response.AddressInfos.length) { return { ok: false, reason: 未识别到有效地址 }; } const info response.AddressInfos[0]; return { ok: true, province: (info.Province || ).trim(), city: (info.City || ).trim(), district: (info.District || ).trim(), street: (info.Street || ).trim(), detail: (info.DetailAddress || ).trim(), name: (info.Name || ).trim(), phone: (info.Phone || ).trim() }; }AddressInfos是数组而不是对象因为一段文本里可能包含多个地址比如“寄到 A 地退回 B 地”。默认取第一个是多数场景的合理选择但做寄件类小程序时最好把数组整个透传给页面让用户自己选。归一化里对每个字段都做了trim别小看这一步接口返回带首尾空格时前端做省市区联动匹配会匹配不上排查起来很费时间。3. 跑起来密钥配置、请求域名与真机调试3.1 密钥该放哪别放前端config/tencent.js里通常是这样的结构// config/tencent.js —— 仅用于本地联调切勿提交到公开仓库 module.exports { secretId: AKIDxxxxxxxxxxxxxxxx, secretKey: xxxxxxxxxxxxxxxxxxxxxxxx, region: ap-guangzhou };新手最容易犯的错是把secretKey直接写进小程序前端然后上传代码。小程序包是可以被解出来看的密钥等于公开。正确做法是自己搭一个极薄的转发服务前端只调自己的域名由服务端持有密钥并完成签名。这个测试工程为了方便演示把签名放在前端你在正式项目里一定要挪走。常见做法是服务端用官方 SDK 完成签名前端只传text字段返回结构保持一致前端代码几乎不用改。3.2 请求域名白名单微信小程序默认只能请求已配置的合法域名。腾讯云 OCR 的接口域名是ocr.tencentcloudapi.com你需要在微信公众平台后台的“开发管理 - 服务器域名”里把它加进 request 合法域名。本地开发阶段可以在开发者工具里勾选“不校验合法域名”但真机预览时这个开关不生效必须配好域名否则请求直接失败且报错信息很含糊。配置完成后在开发者工具里导入项目根目录填入自己的 appid测试可用测试号编译。页面出现输入框后粘贴一段带省市区和电话的地址文本点解析。如果返回鉴权错误先核对时间戳和密钥如果返回空结果换一段更完整的文本再试。3.3 真机调试要看什么真机调试时打开 vConsole重点看三样请求头里的Authorization是否完整、X-TC-Timestamp与当前时间差多少、返回体的Response.Error字段。腾讯云的错误结构是Response.Error.Code加Response.Error.MessageAuthFailure系列基本都是签名或时间问题FailedOperation系列多半是文本里确实没有可识别地址。把这些错误码在封装层里映射成中文提示用户体验会好很多也省得自己反复查文档。4. 避坑与排查五个真实踩过的坑4.1 鉴权失败但密钥没错现象是每次请求都返回AuthFailure.SignatureFailure密钥反复核对无误。原因多半是签名时对请求体的哈希和实际发送的请求体不一致比如先JSON.stringify算了一次哈希发送时又序列化了一次两次结果不同。解决办法是只序列化一次把同一个字符串既用于哈希也用于发送。我一般会在封装层里把payload变量固定下来禁止在发送前再动它。4.2 时间戳偏差导致间歇性失败现象是本地跑得好好的换一台手机就时好时坏。原因是部分设备系统时间不准与服务端偏差超过五分钟签名直接失效。解决办法是在请求前用服务端时间校准或者捕获AuthFailure后提示用户检查系统时间。更稳妥的做法是让服务端代签前端根本不碰时间戳。4.3 返回字段名大小写踩空现象是页面上一片空白但接口明明返回了数据。原因是不同接口版本或不同能力返回的字段名大小写不一致有人按province取实际是Province。解决办法是归一化层统一做一次映射页面只认归一化后的字段永远不直接读原始返回。这个习惯能挡掉大量“接口改了字段名”的连带故障。4.4 合法域名没配导致真机全挂现象是开发者工具正常真机预览全部请求失败。原因是工具里勾了“不校验合法域名”真机不认这个开关。解决办法是在后台把接口域名加进 request 白名单并且注意小程序要求域名必须备案、必须 HTTPS。上线前把工具里的校验开关关掉再完整跑一遍能提前暴露这类问题。4.5 多地址文本只取了第一个现象是用户粘贴“寄件地址 A收件地址 B”结果只解析出 A。原因是归一化时直接取了AddressInfos[0]。解决办法是把数组透传给页面用选择器让用户确认或者在业务层约定输入框只允许单地址并做前端提示。这个坑在寄件场景里出现频率很高别等用户投诉才发现。5. 二次开发把解析能力接进真实下单流程5.1 从测试页到业务页的迁移路径这个工程的价值不在测试页本身而在utils/addressParse.js这层封装。迁移到真实项目时我的做法是保留封装层的函数签名不变把内部实现从“前端直连腾讯云”换成“调自己的服务端接口”。这样页面代码一行不用改密钥也顺势挪到了服务端。服务端收到text后调官方 SDK返回结构对齐normalize的输入前端继续走同一套归一化逻辑。改造前后对比如下维度测试工程做法生产建议做法签名位置前端 JS 计算服务端 SDK 计算密钥存放config/tencent.js服务端环境变量请求域名腾讯云接口域名自有业务域名错误处理控制台打印映射为业务错误码5.2 解析结果如何回填表单真实下单页通常有省市区三级联动选择器。解析出province/city/district后不能直接赋值要先在联动数据里按名称匹配到对应的编码匹配不上就降级为“让用户手动选”。下面这段是回填时的匹配逻辑// 按名称在省市区数据里找编码找不到返回 null 交给用户手选 function matchRegion(regionList, name) { if (!name) return null; const target name.replace(/[省市自治区特别行政区]/g, ); const hit regionList.find(item item.name.replace(/[省市自治区特别行政区]/g, ) target ); return hit ? hit.code : null; }这里去掉后缀再比对是因为接口返回可能带“省”字而本地数据可能不带直接全等匹配会大面积失败。匹配失败不要强行塞一个默认值那会让用户收到寄错地址的包裹宁可让用户多点两下。5.3 验证改造是否成功的三个动作改完之后别只看页面能不能出结果。第一用十段真实脏数据跑一遍包括只有详细地址没有省市的、带多个电话的、中英文混排的看归一化后字段是否合理。第二把服务端密钥临时改错确认前端能给出可读的错误提示而不是白屏。第三在弱网下连续点解析按钮确认没有重复请求把结果覆盖乱。这三步走完基本能挡住上线后的大部分问题。从那以后我每次接地址解析这类第三方能力都强制先把密钥挪到服务端、把归一化层单独写、把错误码映射成中文再谈页面好不好看。这套顺序帮我省下了不少返工。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?