- 小游戏虚拟支付,有退款api吗,没找着?
原问地址……来这里贴一下标签 https://developers.weixin.qq.com/community/develop/doc/0002c4ddb5467856b1299d5e551800?jumpto=comment&commentid=000cae73c08820a6b729ce155514
2019-09-17 - 微信小游戏虚拟支付有退款的开发文档吗~对接一下,没找着文档
你好,小游戏的虚拟支付想要给后台增加退款功能。但是查到了一年以前的答案,只能人工提交申请,最近出了对接的退款文档吗,就像微信公众号支付那样~~~~~
2019-09-17 - 虚拟支付沙箱环境,一直提示-对不起,系统繁忙,怎么解决呀?
入参检查了很多次了,没发现问题呀。 有人支招吗 测试的是,钻石赠送和钻石余额 appid是wx9a07c5856f3999e1
2019-08-21 - 微信客服功能接入自己的服务器后,服务器接受不到消息,但公众号后台有消息
- 当前 Bug 的表现(可附上截图) app_id: wxbec7aebf80022eb2 - 预期表现 服务器接收用户在客服里发送的各类消息 - 复现路径 该app_id对应的服务器URL配置 POST /vx-pub/bridge-in/ 昨天调试的时候,是正常的,可以接受消息。 今天来试,就所有消息都接受不到了,已测: 服务器配置URL/vx-pub/bridge-in/ 接口完好 公众号已认证 消息推送已启用 公众号后台,可接收用户消息 服务器日志结果: 服务器仅在昨日调试时,接入成功了 GET URL/vx-pub/bridge-in/, 并且能通过POST URL/vx-pub/bridge-in/ 收到用户消息,设置好transfer_customer_service后,服务器和公众号后台都可以收到消息。正常 今日再来用时,服务端代码没变,收不到任何消息,偶尔收到几条事件,比如: ``` {"ToUserName":"gh_043fa918d149","FromUserName":"oZKx35IzemCgIIkQr2Bq7sRz0iho","CreateTime":1560909204,"MsgType":"event","Event":"kf_close_session","KfAccount":"kf2001@gh_043fa918d149","CloseType":"TIMEOUT"} [GIN] 2019/06/19 - 09:53:24 | 200 | 156.653µs | 223.166.222.112 | POST /vx-pub/bridge-in/?signature=72aa026743513ff410f4a496afab0c24cef827dc×tamp=1560909204&nonce=1022030466 ``` **但是,公众号后台的消息还是能收到的** - 提供一个最简复现 Demo ```go package main import ( "crypto/sha1" "encoding/hex" "encoding/json" "fmt" "github.com/fwhezfwhez/errorx" "github.com/gin-gonic/gin" "github.com/rs/cors" "io/ioutil" "log" "net/http" "shangraomajiang/util/dependent-services/vx-pub/config" "sort" "strings" "time" ) func main() { r := gin.Default() r.GET("/vx-pub/bridge-in/", BridgeIn) r.POST("/vx-pub/bridge-in/", service) s := &http.Server{ // dev-8301 pro-8300 Addr: config.Port, Handler: cors.AllowAll().Handler(r), ReadTimeout: 60 * time.Second, WriteTimeout: 60 * time.Second, MaxHeaderBytes: 1 << 21, } s.ListenAndServe() } func BridgeIn(c *gin.Context) { signature := c.DefaultQuery("signature", "") timestamp := c.DefaultQuery("timestamp", "") nonce := c.DefaultQuery("nonce", "") echostr := c.DefaultQuery("echostr", "") log.Println(fmt.Sprintf("receive: signature=%s, timestamp=%s, nonce=%s, echostr=%s", signature, timestamp, nonce, echostr)) log.Println(fmt.Sprintf("token=%s", config.Cfg.GetString("token"))) arr := []string{timestamp, nonce, config.Cfg.GetString("token")} sort.Strings(arr) sha1Hash := Sha1(strings.Join(arr, "")) log.Println("sha1Hash=", sha1Hash) if sha1Hash != signature { log.Println("invalid source sha1Hash != signature") } c.String(200, echostr) } func service(c *gin.Context) { type Message struct { // 公有的 ToUserName string FromUserName string CreateTime int64 MsgType string // text,image,miniprogrampage, event MsgId int64 // 文本消息,text Content string // 图片消息, image PicUrl string MediaId string // 小卡片消息,miniprogrampage Title string AppId string PagePath string ThumbUrl string ThumbMediaId string // event // do nothing } type Result struct { ToUserName string FromUserName string CreateTime int64 MsgType string } var message Message defer func() { var in = func(str string, arr []string) bool { for _, v := range arr { if v == str { return true } } return false } if in(message.MsgType, []string{"text", "image", "miniprogrampage"}) { c.JSON(200, Result{ ToUserName: message.FromUserName, FromUserName: message.ToUserName, CreateTime: time.Now().Unix(), MsgType: "transfer_customer_service", }) } else { c.String(200, "success") } }() buf, e := ioutil.ReadAll(c.Request.Body) if e != nil { log.Println(errorx.Wrap(e).Error()) return } if e := json.Unmarshal(buf, &message); e != nil { log.Println(errorx.Wrap(e).Error()) return } fmt.Println(string(buf)) } func Sha1(data string) string { sha := sha1.New() sha.Write([]byte(data)) return hex.EncodeToString(sha.Sum([]byte(nil))) } ```
2019-06-19 - 小游戏midasPay联调不成功mp_sig错误
地址:https://developers.weixin.qq.com/minigame/dev/api-backend/midasPay.html 官方给的测试示例:https://developers.weixin.qq.com/minigame/dev/tutorial/open-ability/midas-signature.html 服务端使用的是go 测试结果: [代码]/[代码][代码]/[代码] [代码]测试sig和mp_sig的生成[代码][代码]func TestGenerateSigAndMpSig(t [代码][代码]*[代码][代码]testing.T) {[代码][代码] [代码][代码]sig, mpSig, e:[代码][代码]=[代码] [代码]GenerateSigAndMpSig(SigParam{[代码][代码] [代码][代码]Openid: [代码][代码]"odkx20ENSNa2w5y3g_qOkOvBNM1g"[代码][代码],[代码][代码] [代码][代码]Appid:[代码][代码]"wx1234567"[代码][代码],[代码][代码] [代码][代码]OfferId: [代码][代码]"12345678"[代码][代码],[代码][代码] [代码][代码]Ts:[代码][代码]1507530737[代码][代码],[代码][代码] [代码][代码]ZoneId:[代码][代码]"1"[代码][代码],[代码][代码] [代码][代码]Pf:[代码][代码]"android"[代码][代码],[代码][代码] [代码][代码]AccessToken: [代码][代码]"ACCESSTOKEN"[代码][代码],[代码][代码] [代码][代码]},[代码][代码]"zNLgAGgqsEWJOg1nFVaO5r7fAlIQxr1u"[代码][代码], [代码][代码]"V7Q38/i2KXaqrQyl2Yx9Hg=="[代码][代码],[代码][代码]"/cgi-bin/midas/getbalance"[代码][代码])[代码] [代码] [代码][代码]if[代码] [代码]e![代码][代码]=[代码][代码]nil {[代码][代码] [代码][代码]t.Fail()[代码][代码] [代码][代码]fmt.Println(e.Error())[代码][代码] [代码][代码]}[代码][代码] [代码][代码]fmt.Println([代码][代码]"sig:"[代码][代码], sig)[代码][代码] [代码][代码]fmt.Println([代码][代码]"mp_sig"[代码][代码], mpSig)[代码][代码]}[代码] [代码]sig: 1ad64e8dcb2ec1dc486b7fdf01f4a15159fc623dc3422470e51cf6870734726b[代码] [代码]mp_sig ff4c5bb39dea1002a8f03be0438724e1a8bcea5ebce8f221f9b9fea3bcf3bf76[代码] 与官方的签名达成了一致,用同样的方法,成功获取了游戏币余额。 但是 midasPay 无论怎么调,都是mp_sig 错误 已经确认了很多遍,midasPay的环境全是sandbox,参数都是正确,然而mp_sig始终错误。 想问一下,bill_no 和amt 难道也参与mp_sig签名吗? 附上一段请求的示例: (请求是按照文档说明请求的,该段示例仅仅是打日志的注解,而不是body里的实际样子) [代码]{[代码][代码] [代码][代码]"param"[代码][代码]: {[代码][代码] [代码][代码]"openid"[代码][代码]: [代码][代码]"oZKx35Nm5ztxziIKxmf6jMTmeOpY"[代码][代码],[代码][代码] [代码][代码]"appid"[代码][代码]: [代码][代码]"wxbec7aebf80022eb2"[代码][代码],[代码][代码] [代码][代码]"offer_id"[代码][代码]: [代码][代码]"1450019844"[代码][代码],[代码][代码] [代码][代码]"ts"[代码][代码]: 1553764538,[代码][代码] [代码][代码]"zone_id"[代码][代码]: [代码][代码]"1"[代码][代码],[代码][代码] [代码][代码]"pf"[代码][代码]: [代码][代码]"android"[代码][代码],[代码][代码] [代码][代码]"amt"[代码][代码]: 1,[代码][代码] [代码][代码]"bill_no"[代码][代码]: [代码][代码]"20190328171538-33586765-exchange_by_shop-diamond-1"[代码][代码],[代码][代码] [代码][代码]"sig"[代码][代码]: [代码][代码]"2f6c54d1061b8bcbc0b4b9fd06ec246a011105d14cf23bbe3a18ffef1978d3f2"[代码][代码],[代码][代码] [代码][代码]"mp_sig"[代码][代码]: [代码][代码]"00ff4bc5b1ae448a987a5de554fa1257b9e57e4b98f143872f815f388a6cb687"[代码][代码] [代码][代码]},[代码][代码] [代码][代码]"url"[代码][代码]: [代码][代码]"https://api.weixin.qq.com/cgi-bin/midas/sandbox/pay?access_token=20_iGmI6zIL98BFi1Aa7MR6VsxMkfRDvwaULTMUFkFOevD_J-a1y02GJG26aLFNDz44LkOuILV2gG5oU1qqa4OF3D_kEfAuct1RFny8OAEOHdvz8T5rNnotUou9VATkIjXYYrZA5MPy-1k3WqarRNAeAIAFBO"[代码][代码]}[代码] 谢指导!!! 下面附上了sig和mp_sig的生成方法 主方法(golang 1.9) [代码]/[代码][代码]/[代码] [代码]获取sig与mp_sig[代码][代码]/[代码][代码]/[代码] [代码]使用实例:[代码][代码]/[代码][代码]*[代码][代码] [代码][代码]sig, mpSig, e:[代码][代码]=[代码] [代码]GenerateSigAndMpSig(SigParam{[代码][代码] [代码][代码]Openid: [代码][代码]"odkx20ENSNa2w5y3g_qOkOvBNM1g"[代码][代码],[代码][代码] [代码][代码]Appid:[代码][代码]"wx1234567"[代码][代码],[代码][代码] [代码][代码]OfferId: [代码][代码]"12345678"[代码][代码],[代码][代码] [代码][代码]Ts:[代码][代码]1507530737[代码][代码],[代码][代码] [代码][代码]ZoneId:[代码][代码]"1"[代码][代码],[代码][代码] [代码][代码]Pf:[代码][代码]"android"[代码][代码],[代码][代码] [代码][代码]AccessToken: [代码][代码]"ACCESSTOKEN"[代码][代码],[代码][代码] [代码][代码]},[代码][代码]"zNLgAGgqsEWJOg1nFVaO5r7fAlIQxr1u"[代码][代码], [代码][代码]"V7Q38/i2KXaqrQyl2Yx9Hg=="[代码][代码],[代码][代码]"/cgi-bin/midas/getbalance"[代码][代码])[代码][代码] [代码][代码]*[代码][代码]/[代码][代码]func GenerateSigAndMpSig(param SigParam, offerSecret string, sessionKey string, orgLoc string) (string, string, error) {[代码][代码] [代码][代码]if[代码] [代码]offerSecret [代码][代码]=[代码][代码]=[代码] [代码]"" {[代码][代码] [代码][代码]return[代码] [代码]"[代码][代码]", "[代码][代码]", errorx.NewFromString("[代码][代码]offerSecret [代码][代码]is[代码] [代码]empty")[代码][代码] [代码][代码]}[代码][代码] [代码][代码]if[代码] [代码]sessionKey [代码][代码]=[代码][代码]=[代码] [代码]"" {[代码][代码] [代码][代码]return[代码] [代码]"[代码][代码]", "[代码][代码]", errorx.NewFromString("[代码][代码]sessionKey [代码][代码]is[代码] [代码]empty")[代码] [代码] [代码][代码]}[代码][代码] [代码][代码]if[代码] [代码]orgLoc [代码][代码]=[代码][代码]=[代码] [代码]"" {[代码][代码] [代码][代码]return[代码] [代码]"[代码][代码]", "[代码][代码]", errorx.NewFromString("[代码][代码]orgLoc [代码][代码]is[代码] [代码]empty")[代码][代码] [代码][代码]}[代码][代码] [代码][代码]if[代码] [代码]param.AccessToken [代码][代码]=[代码][代码]=[代码] [代码]"" {[代码][代码] [代码][代码]return[代码] [代码]"[代码][代码]", "[代码][代码]", errorx.NewFromString("[代码][代码]param.AccessToken [代码][代码]is[代码] [代码]empty")[代码][代码] [代码][代码]}[代码][代码] [代码][代码]if[代码] [代码]param.ZoneId [代码][代码]=[代码][代码]=[代码] [代码]"" {[代码][代码] [代码][代码]return[代码] [代码]"[代码][代码]", "[代码][代码]", errorx.NewFromString("[代码][代码]param.ZoneId [代码][代码]is[代码] [代码]empty")[代码][代码] [代码][代码]}[代码][代码] [代码][代码]if[代码] [代码]param.OfferId [代码][代码]=[代码][代码]=[代码] [代码]"" {[代码][代码] [代码][代码]return[代码] [代码]"[代码][代码]", "[代码][代码]", errorx.NewFromString("[代码][代码]param.OfferId [代码][代码]is[代码] [代码]empty")[代码][代码] [代码][代码]}[代码][代码] [代码][代码]if[代码] [代码]param.Openid [代码][代码]=[代码][代码]=[代码][代码]"" {[代码][代码] [代码][代码]return[代码] [代码]"[代码][代码]", "[代码][代码]", errorx.NewFromString("[代码][代码]param.OpenId [代码][代码]is[代码] [代码]empty")[代码][代码] [代码][代码]}[代码][代码] [代码][代码]if[代码] [代码]param.Appid [代码][代码]=[代码][代码]=[代码] [代码]"" {[代码][代码] [代码][代码]return[代码] [代码]"[代码][代码]", "[代码][代码]", errorx.NewFromString("[代码][代码]param.Appid [代码][代码]is[代码] [代码]empty")[代码][代码] [代码][代码]}[代码][代码] [代码][代码]if[代码] [代码]param.Ts [代码][代码]=[代码][代码]=[代码] [代码]0[代码] [代码]{[代码][代码] [代码][代码]return[代码] [代码]"[代码][代码]", "[代码][代码]", errorx.NewFromString("[代码][代码]param.Ts [代码][代码]is[代码] [代码]empty")[代码][代码] [代码][代码]}[代码][代码] [代码][代码]if[代码] [代码]param.Pf [代码][代码]=[代码][代码]=[代码] [代码]""{[代码][代码] [代码][代码]return[代码] [代码]"[代码][代码]", "[代码][代码]", errorx.NewFromString("[代码][代码]param.Pf [代码][代码]is[代码] [代码]empty")[代码][代码] [代码][代码]}[代码] [代码] [代码][代码]stringA :[代码][代码]=[代码] [代码]common.ToParam(param, [代码][代码]"json"[代码][代码], []string{[代码][代码]"sig"[代码][代码], [代码][代码]"access_token"[代码][代码], [代码][代码]"mp_sig"[代码][代码]}...)[代码][代码] [代码][代码]stringSignTemp :[代码][代码]=[代码] [代码]stringA [代码][代码]+[代码] [代码]fmt.Sprintf([代码][代码]"&org_loc=%s&method=POST&secret=%s"[代码][代码], orgLoc, offerSecret)[代码] [代码] [代码][代码]param.Sig [代码][代码]=[代码] [代码]common.HmacHs256(stringSignTemp, offerSecret)[代码] [代码] [代码][代码]/[代码][代码]/[代码] [代码]获取mp_sig[代码][代码] [代码][代码]stringB :[代码][代码]=[代码] [代码]common.ToParam(param, [代码][代码]"json"[代码][代码], []string{[代码][代码]"mp_sig"[代码][代码]}...)[代码][代码] [代码][代码]stringSignTempB :[代码][代码]=[代码] [代码]stringB [代码][代码]+[代码] [代码]fmt.Sprintf([代码][代码]"&org_loc=%s&method=POST&session_key=%s"[代码][代码], orgLoc, sessionKey)[代码] [代码] [代码][代码]param.MpSig [代码][代码]=[代码] [代码]hmacHs256(stringSignTempB, sessionKey)[代码][代码] [代码][代码]return[代码] [代码]param.Sig, param.MpSig, nil[代码][代码]}[代码] [代码]/[代码][代码]/[代码] [代码]获取hmac[代码][代码]-[代码][代码]hs256 签名[代码][代码]func hmacHs256(message string, secret string) string {[代码][代码] [代码][代码]h :[代码][代码]=[代码] [代码]hmac.New(sha256.New, []byte(secret))[代码][代码] [代码][代码]io.WriteString(h, message)[代码][代码] [代码][代码]return[代码] [代码]fmt.Sprintf([代码][代码]"%x"[代码][代码], h.[代码][代码]Sum[代码][代码](nil))[代码][代码]}[代码] 为什么midasGetBalance成功了,midasPay却 mp_sig异常
2019-03-28 - 现在微信小游戏,使用protobuf,支持proto3吗,具体用哪个包
- 需求的场景描述(希望解决的问题) 因为前端总和我吐槽,他的第三方包支持proto2,想问一下,目前小游戏有支持proto3的包可以用吗 - 希望提供的能力 嗯,同上,支持protobuf3的包
2019-03-12 - 你好,微信小游戏,游戏类的小程序支付额度的限额情况
有了解的来讲一下吗~
2019-02-28 - coupon_id_$n 类似这样的动态的xml节点,参与签名吗
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7&index=8 在这个页面里 订单通知时,返回的结果,是有签名节点的,可是参与节点签名的是有值的参数,因为是response,所以微信是发送方,我们是接受方,我没法预估微信方发来的coupon_id_$n, coupon_type_$n 到底存在不存在,存在几条,那么签名我怎么去验证。 问题的关键不在于 已知一个节点名,他的值是不是零值. ---------------而在于,这个节点名有没有,在定义时,就要预先知道有没有该节点,节点名都是动态的,搞不了呀 来解惑一下,谢谢!
2019-02-27