基于Go语言的微信公众号消息接收与回复实战案例

以下是一个基于Go语言的微信公众号消息接收与回复实战案例,包含详细注释和配置说明:

package main

import (
	"crypto/sha1"
	"encoding/xml"
	"fmt"
	"io"
	"log"
	"net/http"
	"sort"
	"strings"
	"time"
)

// 微信公众号配置信息(需替换为实际值)
const (
	token          = "your_wechat_token"    // 公众号服务器配置Token
	appID          = "your_app_id"          // 公众号AppID
	appSecret      = "your_app_secret"      // 公众号AppSecret
	serverPort     = "8080"                 // 服务器监听端口
)

// TextMessage 接收的文本消息结构体
type TextMessage struct {
	XMLName      xml.Name `xml:"xml"`
	ToUserName   string   `xml:"ToUserName"`
	FromUserName string   `xml:"FromUserName"`
	CreateTime   int64    `xml:"CreateTime"`
	MsgType      string   `xml:"MsgType"`
	Content      string   `xml:"Content"`
	MsgId        int64    `xml:"MsgId"`
}

// TextResponse 文本消息回复结构体
type TextResponse struct {
	XMLName      xml.Name `xml:"xml"`
	ToUserName   CDATA    `xml:"ToUserName"`
	FromUserName CDATA    `xml:"FromUserName"`
	CreateTime   int64    `xml:"CreateTime"`
	MsgType      CDATA    `xml:"MsgType"`
	Content      CDATA    `xml:"Content"`
}

// CDATA 处理XML CDATA标签
type CDATA struct {
	Value string `xml:",cdata"`
}

func main() {
	// 设置路由处理函数
	http.HandleFunc("/wechat", wechatHandler)
	
	// 启动HTTP服务器
	log.Printf("Starting server on :%s...", serverPort)
	err := http.ListenAndServe(":"+serverPort, nil)
	if err != nil {
		log.Fatal("Server start failed: ", err)
	}
}

// 微信消息处理入口
func wechatHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		// 验证服务器地址有效性
		verifyServer(w, r)
	case "POST":
		// 处理用户消息
		processMessage(w, r)
	default:
		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(w, "Method not allowed")
	}
}

// 验证微信服务器(首次配置使用)
func verifyServer(w http.ResponseWriter, r *http.Request) {
	// 获取URL参数
	query := r.URL.Query()
	signature := query.Get("signature")
	timestamp := query.Get("timestamp")
	nonce := query.Get("nonce")
	echostr := query.Get("echostr")

	// 校验签名
	if checkSignature(signature, timestamp, nonce) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(echostr))
		log.Println("Server verification successful")
	} else {
		w.WriteHeader(http.StatusForbidden)
		log.Println("Invalid signature")
	}
}

// 校验签名有效性
func checkSignature(signature, timestamp, nonce string) bool {
	// 将token、timestamp、nonce按字典序排序
	strs := sort.StringSlice{token, timestamp, nonce}
	sort.Sort(strs)
	combined := strings.Join(strs, "")

	// SHA1加密
	hasher := sha1.New()
	hasher.Write([]byte(combined))
	sha := fmt.Sprintf("%x", hasher.Sum(nil))

	return sha == signature
}

// 处理用户消息
func processMessage(w http.ResponseWriter, r *http.Request) {
	// 读取请求体
	body, err := io.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		log.Printf("Error reading body: %v", err)
		return
	}
	defer r.Body.Close()

	// 解析XML消息
	var msg TextMessage
	if err := xml.Unmarshal(body, &msg); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		log.Printf("Error unmarshaling XML: %v", err)
		return
	}

	// 构造回复消息
	response := createTextResponse(msg.FromUserName, msg.ToUserName, "已收到您的消息: "+msg.Content)

	// 序列化为XML
	respXML, err := xml.Marshal(response)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("Error marshaling response: %v", err)
		return
	}

	// 返回响应
	w.Header().Set("Content-Type", "application/xml")
	w.Write(respXML)
}

// 创建文本回复消息
func createTextResponse(toUser, fromUser, content string) TextResponse {
	return TextResponse{
		ToUserName:   CDATA{toUser},
		FromUserName: CDATA{fromUser},
		CreateTime:   time.Now().Unix(),
		MsgType:      CDATA{"text"},
		Content:      CDATA{content},
	}
}

🛠 前置条件

  1. 拥有微信公众平台账号(订阅号或服务号)
  2. 进入公众号后台 -> 开发 -> 基本配置:
    • 启用服务器配置
    • 设置服务器URL(示例:http://your-domain.com/wechat
    • 设置Token(与代码中token常量一致)
  3. 服务器要求:
    • 公网可访问(本地开发可使用ngrok等内网穿透工具)
    • 支持HTTP 80/443端口(若用其他端口需在URL中明确)

📦 依赖项

  • Go 1.16+ 开发环境
  • 标准库:
    • net/http:HTTP服务器
    • encoding/xml:XML处理
    • crypto/sha1:签名验证
    • sort:参数排序

🚨 注意事项

  1. 安全规范:

    • 验证消息来源(必须校验签名)
    • 敏感信息不要硬编码(建议使用环境变量)
    • 生产环境必须使用HTTPS
  2. 消息处理:

    • 微信服务器5秒超时限制
    • 消息去重(通过MsgId)
    • 支持消息加密模式(示例为明文模式)
  3. 服务器配置:

    # 使用ngrok进行内网穿透示例
    ngrok http 8080
    
  4. 运行方式:

    # 设置环境变量(推荐)
    export WECHAT_TOKEN="your_token"
    export WECHAT_APPID="your_appid"
    
    # 编译运行
    go build -o wechat-server
    ./wechat-server
    

🧰 功能扩展建议

  1. 添加消息加解密支持(使用wechat-crypto库)
  2. 支持更多消息类型(图片、语音、事件等)
  3. 集成AccessToken管理
  4. 添加消息日志记录
  5. 实现自定义菜单管理

完整项目结构建议:

/wechat-demo
├── config
│   └── config.go      # 配置管理
├── wechat
│   ├── crypto.go      # 加解密处理
│   ├── message.go     # 消息结构定义
│   └── service.go     # 核心业务逻辑
├── go.mod
└── main.go            # 入口文件

该代码实现了微信公众号基础的消息接收与回复功能,可通过扩展支持更多微信生态功能(菜单、支付、模板消息等)。生产环境使用时请务必添加错误处理、日志记录和监控机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老胖闲聊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值