silenceper / wechat Goto Github PK
View Code? Open in Web Editor NEWWeChat SDK for Go (微信SDK:简单、易用)
Home Page: https://silenceper.com/wechat/
License: Apache License 2.0
WeChat SDK for Go (微信SDK:简单、易用)
Home Page: https://silenceper.com/wechat/
License: Apache License 2.0
2017/08/07 14:42:14 [C] [asm_amd64.s:514] Handler crashed with error http: wrote more than the declared Content-Length
2017/08/07 14:42:14 [C] [asm_amd64.s:514] /usr/local/go/src/runtime/asm_amd64.s:514
2017/08/07 14:42:14 [C] [asm_amd64.s:514] /usr/local/go/src/runtime/panic.go:489
2017/08/07 14:42:14 [C] [asm_amd64.s:514] /opt/gopath/src/github.com/silenceper/wechat/context/render.go:18
2017/08/07 14:42:14 [C] [asm_amd64.s:514] /opt/gopath/src/github.com/silenceper/wechat/context/render.go:25
2017/08/07 14:42:14 [C] [asm_amd64.s:514] /opt/gopath/src/github.com/silenceper/wechat/server/server.go:51
2017/08/07 14:42:14 [C] [asm_amd64.s:514] /opt/gopath/src/jrqs/service/weixinService.go:33
2017/08/07 14:42:14 [C] [asm_amd64.s:514] /opt/gopath/src/jrqs/controllers/message.go:14
2017/08/07 14:42:14 [C] [asm_amd64.s:514] /opt/gopath/src/github.com/astaxie/beego/router.go:798
2017/08/07 14:42:14 [C] [asm_amd64.s:514] /usr/local/go/src/net/http/server.go:2568
2017/08/07 14:42:14 [C] [asm_amd64.s:514] /usr/local/go/src/net/http/server.go:1825
2017/08/07 14:42:14 [C] [asm_amd64.s:514] /usr/local/go/src/runtime/asm_amd64.s:2197
支持小程序授权吗?
hi
brother, oauth is written,but not use?
代码:
wc := wechat.NewWechat(config)
// 传入request和responseWriter
server := wc.GetServer(req, rw)
mu := wc.GetMenu(req, rw)
mu.DeleteMenu()
出错信息:
runtime error: invalid memory address or nil pointer dereference
注意:retrun nil
表示什么也不做
注意:return nil
表示什么也不做
according wechat doc: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
唤起微信支付需要 prepay_id 参数,改参数需要服务器端调用接口生成。
const code2SessionUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"
const openInfoType = 0
type Wechat struct {
*wechat.Wechat
}
type Code2Session struct {
Openid string json:"openid"
SessionKey string json:"session_key"
Unionid string json:"unionid"
ErrCode int64 json:"errcode"
ErrMsg string json:"errMsg"
}
func (w *Wechat) GetCode2Session(code string) (result Code2Session, err error) {
urlStr := fmt.Sprintf(code2SessionUrl, w.Context.AppID, w.Context.AppSecret, code)
var response []byte
response, err = util.HTTPGet(urlStr)
if err != nil {
return
}
err = json.Unmarshal(response, &result)
if err != nil {
return
}
if result.ErrCode != 0 {
err = fmt.Errorf("GetCode2Session error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
return
}
return
}
可以给 cache/redis.go 增加一个指定Redis 对象的方法,由项目统一配置和管理,就不需要组件单独连接了。
//NewRedis 实例化
func SetRedis(pool *redis.Pool) *Redis {
return &Redis{pool}
}
我的代码是这样的
mu := wc.GetMenu(c.Request, c.Writer)
buttons := make([]*menu.Button, 1)
btn := new(menu.Button)
btn.SetClickButton("name", "key123")
buttons[0] = btn
//发送请求
err2 := mu.SetMenu(buttons)
if err2 != nil {
log.Printf("err= %v", err2)
return
}
日志报错是:
err2 := mu.SetMenu(buttons)
这条引发的错误
错误是:
runtime error: invalid memory address or nil pointer dereference
/usr/local/go/src/runtime/panic.go:489 (0x42866f)
/usr/local/go/src/runtime/panic.go:63 (0x42751e)
/usr/local/go/src/runtime/signal_unix.go:290 (0x43d43f)
/Users/xxxx/go/src/github.com/silenceper/wechat/context/access_token.go:36 (0x77651b)
/Users/xxxx/go/src/github.com/silenceper/wechat/menu/menu.go:123 (0x77d0d3)
/Users/xxxx/projects/golang/wx/main.go:57 (0x7863db)
2016/12/13 09:24:04 http: panic serving [::1]:56630: runtime error: invalid memory address or nil pointer dereference
goroutine 5 [running]:
net/http.(*conn).serve.func1(0xc820070100)
/usr/lib/go/src/net/http/server.go:1389 +0xc1
panic(0x7808a0, 0xc82000a130)
/usr/lib/go/src/runtime/panic.go:443 +0x4e9
github.com/silenceper/wechat/context.(*Context).GetAccessToken(0xc8200f2080, 0x0, 0x0, 0x0, 0x0)
/home/xjk/GoCode/src/github.com/silenceper/wechat/context/access_token.go:36 +0x1da
github.com/silenceper/wechat/menu.(*Menu).SetMenu(0xc82004f9c0, 0xc820104008, 0x1, 0x1, 0x0, 0x0)
/home/xjk/GoCode/src/github.com/silenceper/wechat/menu/menu.go:123 +0x48
main.createMenu(0x7f77da1fc820, 0xc8200fe000, 0xc8200e82a0)
/home/xjk/GoProject/wechat/examples/http/http.go:69 +0x617
net/http.HandlerFunc.ServeHTTP(0x89d380, 0x7f77da1fc820, 0xc8200fe000, 0xc8200e82a0)
/usr/lib/go/src/net/http/server.go:1618 +0x3a
net/http.(*ServeMux).ServeHTTP(0xc820016cc0, 0x7f77da1fc820, 0xc8200fe000, 0xc8200e82a0)
/usr/lib/go/src/net/http/server.go:1910 +0x17d
net/http.serverHandler.ServeHTTP(0xc820070080, 0x7f77da1fc820, 0xc8200fe000, 0xc8200e82a0)
/usr/lib/go/src/net/http/server.go:2081 +0x19e
net/http.(*conn).serve(0xc820070100)
/usr/lib/go/src/net/http/server.go:1472 +0xf2e
created by net/http.(*Server).Serve
/usr/lib/go/src/net/http/server.go:2137 +0x44e
2016/12/13 09:24:04 http: panic serving [::1]:56632: runtime error: invalid memory address or nil pointer dereference
goroutine 6 [running]:
net/http.(*conn).serve.func1(0xc820070180)
/usr/lib/go/src/net/http/server.go:1389 +0xc1
panic(0x7808a0, 0xc82000a130)
/usr/lib/go/src/runtime/panic.go:443 +0x4e9
github.com/silenceper/wechat/context.(*Context).GetAccessToken(0xc8200f2200, 0x0, 0x0, 0x0, 0x0)
/home/xjk/GoCode/src/github.com/silenceper/wechat/context/access_token.go:36 +0x1da
github.com/silenceper/wechat/menu.(*Menu).SetMenu(0xc82004f9c0, 0xc820104018, 0x1, 0x1, 0x0, 0x0)
/home/xjk/GoCode/src/github.com/silenceper/wechat/menu/menu.go:123 +0x48
main.createMenu(0x7f77da1fc820, 0xc8200fe1a0, 0xc8200e80e0)
/home/xjk/GoProject/wechat/examples/http/http.go:69 +0x617
net/http.HandlerFunc.ServeHTTP(0x89d380, 0x7f77da1fc820, 0xc8200fe1a0, 0xc8200e80e0)
/usr/lib/go/src/net/http/server.go:1618 +0x3a
net/http.(*ServeMux).ServeHTTP(0xc820016cc0, 0x7f77da1fc820, 0xc8200fe1a0, 0xc8200e80e0)
/usr/lib/go/src/net/http/server.go:1910 +0x17d
net/http.serverHandler.ServeHTTP(0xc820070080, 0x7f77da1fc820, 0xc8200fe1a0, 0xc8200e80e0)
/usr/lib/go/src/net/http/server.go:2081 +0x19e
net/http.(*conn).serve(0xc820070180)
/usr/lib/go/src/net/http/server.go:1472 +0xf2e
created by net/http.(*Server).Serve
/usr/lib/go/src/net/http/server.go:2137 +0x44e
代码如下
func createMenu(rw http.ResponseWriter, req *http.Request) {
//配置微信参数
config := &wechat.Config{
AppID: "ai",
AppSecret: "as",
Token: "token",
EncodingAESKey: "4f9f7ad4b469492a808993f466e3c69889da3cebfcf",
}
wc := wechat.NewWechat(config)
mu := wc.GetMenu(req, rw)
buttons := make([]*menu.Button, 1)
btn := new(menu.Button)
//创建click类型菜单
btn.SetClickButton("name", "key123")
buttons[0] = btn
//设置btn为二级菜单
btn2 := new(menu.Button)
btn2.SetSubButton("subButton", buttons)
buttons2 := make([]*menu.Button, 1)
buttons2[0] = btn2
//发送请求
err := mu.SetMenu(buttons2)
if err != nil {
fmt.Printf("err= %v", err)
return
}
}
可不可以全局定义一个 memcache,多个 http request 共用一个 memcache,使用 Get 方法是否安全,会不会多个请求获取数据产生干扰?
//Message 发送的模板消息内容 type Message struct { ... MiniProgram struct { AppID string
json:"appid"//所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系) **PagePath string
json:"path"** //**官网是pagepath,但是实际上是path,**所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar) }
json:"miniprogram" //可选,跳转至小程序地址 }
Get https://api.weixin.qq.com/sns/oauth2/access_token?appid=&secret=&code=123&grant_type=authorization_code: x509: certificate signed by unknown authority
func (*Js) GetTicket
func (js *Js) GetTicket() (ticketStr string, err error)
GetTicket 获取jsapi_tocket
GetTicket 获取jsapi_ticket
https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=ACCESS_TOKEN
批量获取用户虽然也可以通过作者封装的单个获取api 实现,但是数量一多,效率的弊端很明显
func hello(rw http.ResponseWriter, req *http.Request) {
//打印request基本信息
fmt.Print(req.RequestURI, "\n")
//fmt.Print(req.PostForm, "\n")
//配置微信参数
memcache := cache.NewMemcache("127.0.0.1:11211")
config := &wechat.Config{
AppID: "...",
AppSecret: "...",
Token: "...",
EncodingAESKey: "...",
Cache: memcache,
}
wc := wechat.NewWechat(config)
// 传入request和responseWriter
server := wc.GetServer(req, rw)
fmt.Println(req.URL.RawQuery)
//设置接收消息的处理方法
server.SetMessageHandler(func(msg message.MixMessage) *message.Reply {
//回复消息:演示回复用户发送的消息
text := message.NewText(msg.Content)
fmt.Printf("Message received:%s\n\n", msg.Content)
return &message.Reply{message.MsgTypeText, text}
})
//处理消息接收以及回复
err := server.Serve()
if err != nil {
fmt.Println(err)
return
}
//发送回复的消息
server.Send()
}
以下是一个创建二级菜单的例子
mu := wc.GetMenu(c.Request, c.Writer)
buttons := make([]*menu.Button, 1)
btn := new(menu.Button)
//创建click类型菜单
btn.SetClickButton("name", "key123")
buttons[0] = btn
//设置btn为二级菜单
btn2 := new(menu.Button)
btn2.SetSubButton("subButton", buttons)
buttons2 := make([]*menu.Button, 1)
buttons2[0] = btn2
//发送请求
err := mu.SetMenu(buttons2)
if err != nil {
fmt.Printf("err= %v", err)
return
}
您好,我在使用的过程中遇到了以下错误:
the amount to pad is incorrect: 103
对AES不太了解,不知道是什么原因造成的呢?望赐教
https://github.com/silenceper/wechat/blob/master/util/crypto.go#L139
如果用户在微信公众号打开语音识别,微信返回的消息中会有Recognition string xml:"Recognition"
所以请在message实体中添加,个人已经完成了相关添加。
aReply := message.NewText(“这里是一个跳转URL”)
return &message.Reply{message.MsgTypeText, aReply}
如何给aReply里加上一个超链接呢?如果直接在NewText里使用<a href="跳转URL">跳转URL</a>,貌似是不行的。
里面内容和silenceper/wechat是一样的,由wechat/context/component_access_token.go文件导致
Restful接口都实现了,模板消息接口没有。
模板消息接口是否准备增加呢?谢谢!
这个是例子中的代码,问题是,配置微信参数代码,写在请求回调函数里是不是合适呢?会不会影响效率,还是必须写在这里,不能写在main里?
func hello(rw http.ResponseWriter, req *http.Request) {
//配置微信参数
config := &wechat.Config{
AppID: "your app id",
AppSecret: "your app secret",
Token: "your token",
EncodingAESKey: "your encoding aes key",
}
wc := wechat.NewWechat(config)
// 传入request和responseWriter
server := wc.GetServer(req, rw)
//设置接收消息的处理方法
server.SetMessageHandler(func(msg message.MixMessage) *message.Reply {
//回复消息:演示回复用户发送的消息
text := message.NewText(msg.Content)
return &message.Reply{message.MsgTypeText, text}
})
//处理消息接收以及回复
err := server.Serve()
if err != nil {
fmt.Println(err)
return
}
//发送回复的消息
server.Send()
}
func main() {
http.HandleFunc("/", hello)
err := http.ListenAndServe(":8001", nil)
if err != nil {
fmt.Printf("start server error , err=%v", err)
}
}
获取 AccessToken 需要设置 ip 白名单
开发的时候使用 frp 进行内网穿透方式来调试,ip 不在白名单内
如果可以通过服务器上的代理(服务器 ip 在白名单内)来获取的话会省去很多麻烦
type Config struct {
Timestamp int64
NonceStr string
PrePayID string
SignType string
Sign string
}
调用了Pay.PrePayID只是返回了PrePay_id,可是接下来的支付动作需要用到相关参数,如上面的config所列的参数,可是怎么才能得到这些参数呢?谢谢!
比如说调试接受到数据
type Server struct {
*context.Context
openID string
messageHandler func(message.MixMessage) *message.Reply
requestRawXMLMsg []byte
requestMsg message.MixMessage
responseRawXMLMsg []byte
responseMsg interface{}
isSafeMode bool
random []byte
nonce string
timestamp int64
}
私有不太舒服,建议部分改成大写,或者添加一些公开函数获取.
建议可以配置Redis key前缀,可以用于区分多个项目。
用的是example里的http.go,微信那边配置好了,发送消息到公众号没有回应,用浏览器访问地址会打印请求校验失败
这个代码很规范,谢谢!
用的example里的代码,仅仅改了监听端口,在debug时该错误反复出现,但是直接运行编译后的exe,没有错误输出。但是该错误似乎对功能没有任何影响。
package main
import (
"fmt"
"net/http"
"github.com/silenceper/wechat"
"github.com/silenceper/wechat/message"
)
func hello(rw http.ResponseWriter, req *http.Request) {
//配置微信参数
config := &wechat.Config{
AppID: "...",
AppSecret: "...",
Token: "...",
EncodingAESKey: "...",
}
wc := wechat.NewWechat(config)
// 传入request和responseWriter
server := wc.GetServer(req, rw)
//设置接收消息的处理方法
server.SetMessageHandler(func(msg message.MixMessage) *message.Reply {
//回复消息:演示回复用户发送的消息
text := message.NewText(msg.Content)
return &message.Reply{message.MsgTypeText, text}
})
//处理消息接收以及回复
err := server.Serve()
if err != nil {
fmt.Println(err)
return
}
//发送回复的消息
server.Send()
}
func main() {
http.HandleFunc("/", hello)
err := http.ListenAndServe(":80", nil)
if err != nil {
fmt.Printf("start server error , err=%v", err)
}
}
如何响应菜单事件呢?有示例么?谢谢!
It's seems master branch is stable enough for production usage now.
golang新手:content 获取token的时候为什么要加锁呢 ?
感觉JSON配置起来非常方便,建议楼主通过提供一个函数:SetMenuByJson(JsonFileName string)来创建菜单,这样最好了.因为菜单可以通过记事本来灵活配置,非常方便的.
感谢楼主的辛勤付出!
E:/software/Go/src/runtime/asm_amd64.s:573
E:/software/Go/src/runtime/panic.go:502
E:/software/Go/src/runtime/panic.go:63
E:/software/Go/src/runtime/signal_windows.go:167
E:/go_working_space/src/github.com/silenceper/wechat/context/access_token.go:36
E:/go_working_space/src/github.com/silenceper/wechat/menu/menu.go:123
E:/go_working_space/src/weiboxs.com/new_h_archives/services/WechatApiService.go:54
E:/go_working_space/src/weiboxs.com/new_h_archives/controllers/backend/WechatController.go:100
E:/software/Go/src/runtime/asm_amd64.s:573
E:/software/Go/src/reflect/value.go:447
E:/software/Go/src/reflect/value.go:308
E:/go_working_space/src/github.com/astaxie/beego/router.go:847
E:/software/Go/src/net/http/server.go:2694
E:/software/Go/src/net/http/server.go:1830
E:/software/Go/src/runtime/asm_amd64.s:2361
求指导
template 里面 调用send()方法时,
accessToken, err = tpl.GetAccessToken() 后面GetAccessToken()方法好像没有实现呀,
accessToken 这个值传不进去呢
新手问下这里该怎么处理,有方法传值进去吗?
发布微信菜单时,如果有VIEWBUTTON的url里面带有&符号,json.Marshal会转义成\u0026,微信会返回40033错误!!!
代码如下:
func WechatConfig() {
appid := beego.AppConfig.String("appid")
appsecret := beego.AppConfig.String("appsecret")
config := &wechat.Config{
AppID: appid,
AppSecret: appsecret,
Token: beego.AppConfig.String("token"),
EncodingAESKey: beego.AppConfig.String("encodingAESKey"),
}
wc := wechat.NewWechat(config)
fmt.Println(wc.GetAccessToken())
}
在使用wc.GetAccessToken就出现:
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x28 pc=0x81e58e]
goroutine 1 [running]:
github.com/silenceper/wechat/context.(*Context).GetAccessToken(0xc0420fa080, 0x0, 0x0, 0x0, 0x0)
D:/gowork/src/github.com/silenceper/wechat/context/access_token.go:36 +0x13e
github.com/silenceper/wechat.(*Wechat).GetAccessToken(0xc04206bec0, 0xc0421490e0, 0x9, 0xc04204eb00, 0x20)
D:/gowork/src/github.com/silenceper/wechat/wechat.go:58 +0x35
cdbcb/models.WechatConfig()
D:/gowork/src/cdbcb/models/wechat.go:20 +0x27a
main.main()
D:/gowork/src/cdbcb/main.go:11 +0x29
目前不知道是哪个位置出现了无效指针
请问支持企业号吗
对于直接跳转的菜单点击,发现事件类型是view。
但点击菜单,在公众号正文中返回了一个图文标题,需要点击这个标题才能进入。这个事件类型按理应该是click类型(对吧),但用本project调用时发现没有对应的事件。
请问这是因为个人公众号没有认证的原因,还是其他问题?
The XML message returned in the official document of WeChat is required with CDATA, but it is not implemented in this package
目前只支持get set delete 导致目前我项目中使用了两个redis相关依赖
redisOpts := cache.RedisOpts{
Host: redisServerAddr,
Password: redisServerPwd,
}
redis = cache.NewRedis(&redisOpts)
client = Redis.NewClient(&Redis.Options{
Addr: redisServerAddr,
Password: redisServerPwd, // no password set
DB: 0, // use default DB
})
_, err := client.Ping().Result()
if err != nil {
panic(err)
}
建议增加个基于内存的缓存实现
用的是 beego,直接 ServerJSON(),没想到大小写的问题,浪费了一天排查,今天早上才意识到这个问题,极度郁闷。
好像只能使用 redigo 这个 redis 插件,go-redis 这个插件用不了。
如题
打印出timestamp, nonce, signature都是空的
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.