微信公眾號開發「服務器配置」步驟:微信發送 GET 請求攜帶 signature、timestamp、nonce、echostr,開發者需驗證簽名後**原樣返回 echostr**。許多新手以為「收到參數並打印了 echostr 就行」,實則返回格式、簽名算法、字符編碼任一環節出錯即配置失敗。
token、timestamp、nonce 三個參數進行字典序排序。signature 對比,標識該請求來源於微信。| 現象 | 根因 | 修正 |
|---|---|---|
| 返回 "success" / "ok" / JSON | 誤以為需返回狀態碼 | **必須原樣返回 echostr 字符串** |
| 返回帶換行/空格的 echostr | System.out.println / 模板引擎輸出 | 用 response.getWriter().write(echostr) 或 response.getWriter().print(echostr) |
| 簽名算法錯誤 | 排序方式錯、編碼錯、大小寫錯 | 嚴格按字典序、UTF-8、SHA1 十六進制小寫 |
| Token 不一致 | 公眾平台填寫的 Token 與代碼常量不一致 | 雙向核對,建議從配置中心讀取 |
| HTTPS 證書不受信 | 自簽證書/過期/域名不匹配 | 用有效 CA 證書,或內網穿透工具 (ngrok/frp) 提供 HTTPS |
| 端口非 80/443 | 微信只回調 80/443 | Nginx 反向代理轉發至內部端口 |
@WebServlet("/wx/verify")
public class WxVerifyServlet extends HttpServlet {
private static final String TOKEN = "your_token_from_config";
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String signature = req.getParameter("signature");
String timestamp = req.getParameter("timestamp");
String nonce = req.getParameter("nonce");
String echostr = req.getParameter("echostr");
// 1. 參數校驗
if (signature == null || timestamp == null || nonce == null || echostr == null) {
resp.setStatus(400);
return;
}
// 2. 簽名驗證
String[] arr = {TOKEN, timestamp, nonce};
Arrays.sort(arr); // 字典序
String sortedStr = String.join("", arr);
String sha1 = SHA1Util.encode(sortedStr); // 自行實現或用 Commons Codec
if (!sha1.equals(signature)) {
resp.setStatus(403); // 簽名失敗
return;
}
// 3. 關鍵:原樣返回 echostr,設置 Content-Type=text/plain
resp.setContentType("text/plain; charset=UTF-8");
resp.getWriter().write(echostr); // 不要用 println/print 避免換行
resp.getWriter().flush();
}
}
「排序拼接 SHA1,匹配才算過;原樣返回 echostr,多一字節都算錯。」
配置失敗 90% 是「返回格式不對」或「Token 不一致」。對照清單逐項核對,分分鐘搞定。