package wechatwork import ( "fmt" "os" "sync" "github.com/dfang/wechat-work-go/cache" "gopkg.in/resty.v1" ) // WechatWork 企业微信客户端 type WechatWork struct { // CorpID 企业 ID,必填 CorpID string } // App 企业微信客户端(分应用) type App struct { *WechatWork // CorpSecret 应用的凭证密钥,其实应该叫AgentSecret更好,必填 CorpSecret string // AgentID 应用 ID,必填 AgentID int64 AccessToken string // Token string `json:"access_token"` ExpiresIn int `json:"expires_in"` accessTokenLock *sync.RWMutex Cache cache.Cache } // New 构造一个 WechatWork 对象,需要提供企业 ID // // 通常,要使用wechat-work-go, 你需要先创建一个 WechatWork 的对象, // 接着以此对象调用 WithApp 创建一个app // 然后就可以以app对象调用API了 // // 企业微信API是分应用的 // // 简单来说就是 a 应用的CORP_SECRET 和 AGENT_ID 获取的access_token 是不能操作 b应用的 // // CORP_ID 去企业微信管理中的 我的企业 最底部 // CORP_SECRET 其实是应用的secret,个人感觉应该叫AgentSecret 或 AppSecret 更合适, 但因为api接口和官方文档叫corpSecret,所以不改变 // AGENT_ID 应用的ID, CORP_SECRET 和 AGENT_ID 都去应用的详情页面找 // // 示例代码: // // corpID := os.Getenv("CORP_ID") // corpSecret := os.Getenv("CORP_SECRET") // agentID, _ := strconv.ParseInt(os.Getenv("AGENT_ID"), 10, 64) // corp := wechatwork.New(corpID) // app = corp.NewApp(corpSecret, agentID) // func New(corpID string) *WechatWork { return &WechatWork{ CorpID: corpID, } } // NewApp 构造本企业下某自建 app 的对象 // // 企业微信暂未提供创建 app 的 api, 创建应用需要去企业微信的管理后台中 // func (corp *WechatWork) NewApp(corpSecret string, agentID int64) *App { return &App{ WechatWork: corp, CorpSecret: corpSecret, AgentID: agentID, AccessToken: "", accessTokenLock: &sync.RWMutex{}, Cache: cache.NewMemory(), } } // newDefaultRestyClient 返回一个resty 的client func newDefaultRestyClient() *resty.Client { client := resty.New() client.SetDebug(os.Getenv("DEBUG") == "true") client.SetLogger(os.Stdout) client.SetHostURL("https://qyapi.weixin.qq.com") return client } // SimpleGet 一切get请求的api调用可使用此方法 // // 企业微信中,获取操作和删除都是GET请求 // // just like resty.SetReult(&respObj).Get(url) // // note: url must be full, if you're consuming this library, you don't need this method, have to export this method for other packages to call func (app *App) SimpleGet(url string, respObj interface{}) error { resp, err := newDefaultRestyClient().R(). SetHeader("Accept", "application/json"). SetResult(&respObj). Get(url) if err != nil { fmt.Fprintln(os.Stdout, resp.Body()) panic(err) } return nil } // SimplePost 一切Post请求的api调用使用此方法 // // 企业微信中,删除操作一般都是GET请求,更新操作、批量删除成员是POST请求,没有PUT、PATCH、DELETE // // just like resty.SetBody(b).SetReult(&respObj).Post(url) // // resty can Automatically marshal and unmarshal // // note: url must be full, if you're consuming this library, you don't need this method, have to export this method for other packages to call func (app *App) SimplePost(url string, body interface{}, respObj interface{}) error { resp, err := newDefaultRestyClient().R(). SetHeader("Content-Type", "application/json"). SetBody(body). SetResult(&respObj). Post(url) if err != nil { fmt.Fprintln(os.Stdout, resp.Body()) panic(err) } return nil } // RespCommon Comman Response Struct type RespCommon struct { ErrCode int `json:"errcode"` ErrMsg string `json:"errmsg"` } // IsOK 响应体是否为一次成功请求的响应 // // 实现依据: https://work.weixin.qq.com/api/doc#10013 // // > 企业微信所有接口,返回包里都有errcode、errmsg。 // // > 开发者需根据errcode是否为0判断是否调用成功(errcode意义请见全局错误码)。 // // > 而errmsg仅作参考,后续可能会有变动,因此不可作为是否调用成功的判据。 func (x *RespCommon) IsOK() bool { return x.ErrCode == 0 }
WechatWork 企业微信客户端发送请求源码
66 min read