76 lines
2.1 KiB
Go
76 lines
2.1 KiB
Go
// Package wechat 封装微信小程序相关调用(此处为 code2session 实现)。
|
|
package wechat
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"portal-mini-go/internal/pkg/errors"
|
|
)
|
|
|
|
const code2SessionURL = "https://api.weixin.qq.com/sns/jscode2session"
|
|
|
|
// SessionInfo 是 code2session 返回的会话信息。
|
|
type SessionInfo struct {
|
|
OpenID string
|
|
UnionID string
|
|
SessionKey string
|
|
}
|
|
|
|
// Client 微信调用客户端。凭证(appid/secret)由调用方按请求传入,
|
|
// 不再依赖静态配置,方便后台动态纳管多个小程序。
|
|
type Client struct {
|
|
client *http.Client
|
|
}
|
|
|
|
func NewClient() *Client {
|
|
return &Client{client: &http.Client{}}
|
|
}
|
|
|
|
// Code2Session 用 appID + secret + 登录 code 换取 openid / session_key。
|
|
func (c *Client) Code2Session(ctx context.Context, appID, secret, code string) (*SessionInfo, error) {
|
|
q := url.Values{}
|
|
q.Set("appid", appID)
|
|
q.Set("secret", secret)
|
|
q.Set("js_code", code)
|
|
q.Set("grant_type", "authorization_code")
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, code2SessionURL+"?"+q.Encode(), nil)
|
|
if err != nil {
|
|
return nil, errors.Wrap(50000, "build wechat request", err)
|
|
}
|
|
|
|
resp, err := c.client.Do(req)
|
|
if err != nil {
|
|
return nil, errors.Wrap(50000, "call wechat code2session", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, errors.Wrap(50000, "read wechat response", err)
|
|
}
|
|
|
|
var r struct {
|
|
OpenID string `json:"openid"`
|
|
UnionID string `json:"unionid"`
|
|
SessionKey string `json:"session_key"`
|
|
ErrCode int `json:"errcode"`
|
|
ErrMsg string `json:"errmsg"`
|
|
}
|
|
if err := json.Unmarshal(body, &r); err != nil {
|
|
return nil, errors.Wrap(50000, "decode wechat response", err)
|
|
}
|
|
if r.ErrCode != 0 {
|
|
slog.Warn("wechat code2session error", slog.Int("errcode", r.ErrCode), slog.String("errmsg", r.ErrMsg))
|
|
return nil, errors.Wrap(50000, fmt.Sprintf("wechat code2session: %s", r.ErrMsg), nil)
|
|
}
|
|
|
|
return &SessionInfo{OpenID: r.OpenID, UnionID: r.UnionID, SessionKey: r.SessionKey}, nil
|
|
}
|