Gin, the Web framework of Go language, is used to access wechat public accounts, and to receive and reply wechat messages.
Meanwhile, nginx proxy server is used to optimize the port number and URI of proxy.
The project address for the Demo is given at the end of the article.
directory
- Public Account access
- The message received
- Reply message
- Use the Ngxin proxy server
- summary
Public Account access
The interface test number provided by wechat public platform is used for development and application.
There are two main steps to access the public account. Access guide for wechat public platform:
- Filling in the Server Configuration
- Verify the validity of the server address
The first step is to set the URL of the server. The URL must start with http:// or https://, which supports port 80 and port 443 respectively. You also need to configure a Token of 3 to 32 characters for message authentication.
The second step is used to verify the correctness of the message source. After the configuration in the first step is completed and submission is clicked, the wechat server will send a GET request to the server address filled in. The parameters and description of the GET request are shown in the following table:
parameter | describe |
---|---|
signature | Wechat encryption signature and signature combine token parameters filled in by the developer with timestamp parameters and nonce parameters in the request. |
timestamp | The time stamp |
nonce | The random number |
echostr | Random string |
The server verification process is as follows:
- right
token
,timestamp
,nonce
Lexicographical sorting of three parameters; - I’m going to sort that
token
,timestamp
,nonce
The three arguments are sequentially concatenated into a string and are performed on the stringsha1
Encryption; - Use the encrypted string and
signature
If the string values are the same, the verification passesechostr
The parameter is returned as is.
The access code of wechat public account realized by Go is as follows:
package main
import (
"github.com/gin-gonic/gin"
"log"
"weixin-demo/util"
)
// The Token is the same as that specified in the server configuration
const Token = "coleliedev"
func main(a) {
router := gin.Default()
router.GET("/wx", WXCheckSignature)
log.Fatalln(router.Run(": 80"))}// WXCheckSignature verify wechat access
func WXCheckSignature(c *gin.Context) {
signature := c.Query("signature")
timestamp := c.Query("timestamp")
nonce := c.Query("nonce")
echostr := c.Query("echostr")
ok := util.CheckSignature(signature, timestamp, nonce, Token)
if! ok { log.Println("Wechat public account access verification failed!")
return
}
log.Println("Wechat public account access verification success!")
_, _ = c.Writer.WriteString(echostr)
}
Copy the code
package util
import (
"crypto/sha1"
"encoding/hex"
"sort"
"strings"
)
// CheckSignature check wechat public id signature
func CheckSignature(signature, timestamp, nonce, token string) bool {
arr := []string{timestamp, nonce, token}
// lexicographical sort
sort.Strings(arr)
n := len(timestamp) + len(nonce) + len(token)
var b strings.Builder
b.Grow(n)
for i := 0; i < len(arr); i++ {
b.WriteString(arr[i])
}
return Sha1(b.String()) == signature
}
// Encode Sha1
func Sha1(str string) string {
h := sha1.New()
h.Write([]byte(str))
return hex.EncodeToString(h.Sum(nil))}Copy the code
Finally, deploy the project to the server and click the submit button in the interface configuration information to complete the access of the wechat public account.
Note that since this Web application listens on port 80, the server cannot have other programs that listen on port 80, such as nginx.
The message received
After the wechat public account is connected, the two apis of ordinary message reception and passive reply to user messages are taken as examples to complete the specific implementation of Go’s reception and reply processing of wechat messages.
The first is message reception. Refer to official wechat documents to receive ordinary messages.
When ordinary wechat users send messages to public accounts, the wechat server sends the XML packet of the POST message to the URL filled in by the developer.
Take text message as an example, its XML packet structure and parameter description are as follows:
<xml>
<ToUserName><! [CDATA[toUser]]></ToUserName>
<FromUserName><! [CDATA[fromUser]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><! [CDATA[text]]></MsgType>
<Content><! [CDATA[this is a test]]></Content>
<MsgId>1234567890123456</MsgId>
</xml>
Copy the code
parameter | describe |
---|---|
ToUserName | Developer wechat account |
FromUserName | Sender account (one OpenID) |
CreateTime | Message creation time (integer) |
MsgType | The message type is text |
Content | Text message content |
MsgId | The message ID is a 64-bit integer |
After understanding the way in which wechat server transmits wechat user messages to the development server and the packet structure transmitted, we know that there are roughly two steps for message reception and development:
- Create handles the wechat server sent to the development server
POST
Handlers for type requests; - On the request
XML
The packet is parsed.
For the second step, we can use the Gin framework’s ShouldBindXML or BindXML method to parse the XML packets.
The message receiving code implemented with Go is as follows:
package main
import (
"github.com/gin-gonic/gin"
"log"
"weixin-demo/util"
)
const Token = "coleliedev"
func main(a) {
router := gin.Default()
router.GET("/wx", WXCheckSignature)
router.POST("/wx", WXMsgReceive)
log.Fatalln(router.Run(": 80"))}// WXTextMsg wechat text message structure
type WXTextMsg struct {
ToUserName string
FromUserName string
CreateTime int64
MsgType string
Content string
MsgId int64
}
// WXMsgReceive receives wechat messages
func WXMsgReceive(c *gin.Context) {
var textMsg WXTextMsg
err := c.ShouldBindXML(&textMsg)
iferr ! =nil {
log.Printf("[message receive] -XML packet parsing failure: %v\n", err)
return
}
log.Printf("[Message receive] - Received message with type %s and content %s\n", textMsg.MsgType, textMsg.Content)
}
Copy the code
After updating the code for adding messages to receive to the server, a message is sent to the interface test number. The following records can be viewed on the server:
Reply message
Next, the API of passive reply to user messages is taken as an example to realize the reply to messages sent by wechat users. Refer to wechat official documents for passive reply.
Message reply and message receiving are similar in that both require data packets in XML format. The structure and parameters of XML data packets required for text message reply are as follows:
<xml>
<ToUserName><! [CDATA[toUser]]></ToUserName>
<FromUserName><! [CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><! [CDATA[text]]></MsgType>
<Content><! [CDATA [you]] ></Content>
</xml>
Copy the code
parameter | Whether must | describe |
---|---|---|
ToUserName | is | Recipient account (OpenID received) |
FromUserName | is | Developer wechat account |
CreateTime | is | Message creation time (integer) |
MsgType | is | The message type is text |
Content | is | Message content of the reply (line break: line break can be used in content, wechat client supports line break display) |
The message reply code implemented with Go is as follows:
package main
import (
"encoding/xml"
"fmt"
"github.com/gin-gonic/gin"
"log"
"time"
"weixin-demo/util"
)
const Token = "coleliedev"
func main(a) {
router := gin.Default()
router.GET("/wx", WXCheckSignature)
router.POST("/wx", WXMsgReceive)
log.Fatalln(router.Run(": 80"))}// WXMsgReceive receives wechat messages
func WXMsgReceive(c *gin.Context) {
var textMsg WXTextMsg
err := c.ShouldBindXML(&textMsg)
iferr ! =nil {
log.Printf("[message receive] -XML packet parsing failure: %v\n", err)
return
}
log.Printf("[Message receive] - Received message with type %s and content %s\n", textMsg.MsgType, textMsg.Content)
// Passively responds to received messages
WXMsgReply(c, textMsg.ToUserName, textMsg.FromUserName)
}
// WXRepTextMsg wechat reply text message structure
type WXRepTextMsg struct {
ToUserName string
FromUserName string
CreateTime int64
MsgType string
Content string
// If XMLName is not marked, the parsed XML is the name of the structure
XMLName xml.Name `xml:"xml"`
}
// WXMsgReply replies to wechat messages
func WXMsgReply(c *gin.Context, fromUser, toUser string) {
repTextMsg := WXRepTextMsg{
ToUserName: toUser,
FromUserName: fromUser,
CreateTime: time.Now().Unix(),
MsgType: "text",
Content: fmt.Sprintf("[message reply] - %s", time.Now().Format("The 2006-01-02 15:04:05")),
}
msg, err := xml.Marshal(&repTextMsg)
iferr ! =nil {
log.Printf("[message reply] - Error encoding object XML: %v\n", err)
return
}
_, _ = c.Writer.Write(msg)
}
Copy the code
Note that the XMLName attribute must be added to the WXRepTextMsg structure and the XML tag must be applied to mark the XML name as XML. That is, after encoding the structure object using the xml.Marshal method, The outermost tag of the resulting XML data is < XML >
. If the XMLName attribute is not added, the outermost tag of the encoded XML data is
cannot be successfully replied.
After updating the code to add message reply to the server, sending a message to the server will receive the following reply:
Use the Nginx proxy server
Usually the server will not give port 80 or 443 to the Web program, then you can use nginx as a proxy server, run the Web program on other ports, such as 8002, let Nginx listen to port 80 or 443, and the specified URI reverse proxy operation. If the following configuration is used, the request on port 80 URI /weixin will be proxied to /wx on port 8002 locally on the server:
server {
listen 80;
location /weixin {
proxy_pass http://127.0.0.1:8002/wx;
proxy_redirectdefault; }}Copy the code
Change the program listening port number to 8002:
func main(a) {
router := gin.Default()
router.GET("/wx", WXCheckSignature)
router.POST("/wx", WXMsgReceive)
log.Fatalln(router.Run(": 8002"))}Copy the code
Modify the configuration of wechat public account access interface:
The final test results are as follows:
From the log file of nginx, it can be seen that it did receive a request with the URI /weixin, and in the log file of the Web program, it can also be seen that it received a request with the URI /wx. By observing the request parameters recorded in the two logs, it can be found that, Nginx is a successful proxy.
summary
Finally, a summary of this article is made. This article mainly uses the Gin framework of Go language and the wechat interface test number to complete the development of wechat public account access, and realize the two functions of receiving and replying wechat user messages.
And thank you for your patience!!
Github address: github.com/hkail/weixi…
Gitee address: gitee.com/hkail/weixi…