golang 实现微信公众平台API引擎开发模式

songbohr · · 2838 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。


/*
 *@author 菠菜君
 *@Version 0.2
 *@time 2013-10-29
 *@golang实现微信公众平台API引擎开发模式
 *@青岛程序员 微信订阅号	qdprogrammer
 *@Golang 微信订阅号	gostock
 *@关于青岛程序员的技术,创业,生活 分享。
 *@开源 https://github.com/philsong/
 */
package main

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

const (
	TOKEN    = "gostock"
	Text     = "text"
	Location = "location"
	Image    = "image"
	Link     = "link"
	Event    = "event"
	Music    = "music"
	News     = "news"
)

type msgBase struct {
	ToUserName   string
	FromUserName string
	CreateTime   time.Duration
	MsgType      string
	Content      string
}

type Request struct {
	XMLName                xml.Name `xml:"xml"`
	msgBase                         // base struct
	Location_X, Location_Y float32
	Scale                  int
	Label                  string
	PicUrl                 string
	MsgId                  int
}

type Response struct {
	XMLName xml.Name `xml:"xml"`
	msgBase
	ArticleCount int     `xml:",omitempty"`
	Articles     []*item `xml:"Articles>item,omitempty"`
	FuncFlag     int
}

type item struct {
	XMLName     xml.Name `xml:"item"`
	Title       string
	Description string
	PicUrl      string
	Url         string
}

func weixinEvent(w http.ResponseWriter, r *http.Request) {
	if weixinCheckSignature(w, r) == false {
		fmt.Println("auth failed, attached?")
		return
	}

	fmt.Println("auth success, parse POST")

	defer r.Body.Close()

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal(err)
		return
	}

	fmt.Println(string(body))
	var wreq *Request
	if wreq, err = DecodeRequest(body); err != nil {
		log.Fatal(err)
		return
	}

	wresp, err := dealwith(wreq)
	if err != nil {
		log.Fatal(err)
		return
	}

	data, err := wresp.Encode()
	if err != nil {
		fmt.Printf("error:%v\n", err)
		return
	}

	fmt.Println(string(data))
	fmt.Fprintf(w, string(data))
	return
}

func dealwith(req *Request) (resp *Response, err error) {
	resp = NewResponse()
	resp.ToUserName = req.FromUserName
	resp.FromUserName = req.ToUserName
	resp.MsgType = Text

	if req.MsgType == Event {
		if req.Content == "subscribe" {
			resp.Content = "欢迎关注微信订阅号qdprogrammer, 分享青岛程序员的技术,创业,生活。"
			return resp, nil
		}
	}

	if req.MsgType == Text {
		if strings.Trim(strings.ToLower(req.Content), " ") == "help" {
			resp.Content = "欢迎关注微信订阅号qdprogrammer, 分享青岛程序员的技术,创业,生活。"
			return resp, nil
		}
		resp.Content = "亲,菠菜君已经收到您的消息, 将尽快回复您."
	} else if req.MsgType == Image {

		var a item
		a.Description = "雅蠛蝶。。。^_^^_^1024你懂的"
		a.Title = "雅蠛蝶图文测试"
		a.PicUrl = "http://static.yaliam.com/gwz.jpg"
		a.Url = "http://blog.csdn.net/songbohr"

		resp.MsgType = News
		resp.ArticleCount = 1
		resp.Articles = append(resp.Articles, &a)
		resp.FuncFlag = 1
	} else {
		resp.Content = "暂时还不支持其他的类型"
	}
	return resp, nil
}

func weixinAuth(w http.ResponseWriter, r *http.Request) {
	if weixinCheckSignature(w, r) == true {
		var echostr string = strings.Join(r.Form["echostr"], "")
		fmt.Fprintf(w, echostr)
	}
}

func weixinHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		fmt.Println("GET begin...")
		weixinAuth(w, r)
		fmt.Println("GET END...")
	} else {
		fmt.Println("POST begin...")
		weixinEvent(w, r)
		fmt.Println("POST END...")
	}
}

func main() {
	http.HandleFunc("/check", weixinHandler)
	//http.HandleFunc("/", action)
	port := "80"
	println("Listening on port ", port, "...")
	err := http.ListenAndServe(":"+port, nil) //设置监听的端口

	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func str2sha1(data string) string {
	t := sha1.New()
	io.WriteString(t, data)
	return fmt.Sprintf("%x", t.Sum(nil))
}

func weixinCheckSignature(w http.ResponseWriter, r *http.Request) bool {
	r.ParseForm()
	fmt.Println(r.Form)

	var signature string = strings.Join(r.Form["signature"], "")
	var timestamp string = strings.Join(r.Form["timestamp"], "")
	var nonce string = strings.Join(r.Form["nonce"], "")
	tmps := []string{TOKEN, timestamp, nonce}
	sort.Strings(tmps)
	tmpStr := tmps[0] + tmps[1] + tmps[2]
	tmp := str2sha1(tmpStr)
	if tmp == signature {
		return true
	}
	return false
}

func DecodeRequest(data []byte) (req *Request, err error) {
	req = &Request{}
	if err = xml.Unmarshal(data, req); err != nil {
		return
	}
	req.CreateTime *= time.Second
	return
}

func NewResponse() (resp *Response) {
	resp = &Response{}
	resp.CreateTime = time.Duration(time.Now().Unix())
	return
}

func (resp Response) Encode() (data []byte, err error) {
	resp.CreateTime = time.Duration(time.Now().Unix())
	data, err = xml.Marshal(resp)
	return
}



有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:songbohr

查看原文:golang 实现微信公众平台API引擎开发模式

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2838 次点击  
加入收藏 微博
1 回复  |  直到 2019-07-23 15:47:33
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传