-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathweibo.go
173 lines (159 loc) · 5.05 KB
/
weibo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package gobo
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
)
// Params类型用来表达微博API的JSON输入参数。注意:
// 1. Params不应当包含访问令牌(access_token),因为它已经是Call和Upload函数的参数
// 2. 在Upload函数中,Params参数不应当包含pic参数,上传的图片内容和类型应当通过reader和imageFormat指定
type Params map[string]interface{}
// Weibo结构体定义了微博API调用功能
type Weibo struct {
httpClient http.Client
}
// 调用微博API
//
// 该函数可用来调用除了statuses/upload(见Upload函数)和微博授权(见Authenticator结构体)外的所有微博API。
//
// 输入参数
// method API方法名,比如 "/statuses/user_timeline" 又如 "comments/show"
// httpMethod HTTP请求方式,只能是"get"或者"post"之一,否则出错
// token 用户授权的访问令牌
// params JSON输入参数,见Params结构体的注释
// response API服务器的JSON输出将被还原成该结构体
//
// 当出现异常时输出非nil错误
func (weibo *Weibo) Call(method string, httpMethod string, token string, params Params, response interface{}) error {
apiUri := fmt.Sprintf("%s/%s/%s%s", ApiDomain, ApiVersion, method, ApiNamePostfix)
if httpMethod == "get" {
return weibo.sendGetHttpRequest(apiUri, token, params, response)
} else if httpMethod == "post" {
return weibo.sendPostHttpRequest(apiUri, token, params, nil, "", response)
}
return &ErrorString{"HTTP方法只能是\"get\"或者\"post\""}
}
// 调用/statuses/upload发带图片微博
//
// 输入参数
// token 用户授权的访问令牌
// params JSON输入参数,见Params结构体的注释
// reader 包含图片的二进制流
// imageFormat 图片的格式,比如 "jpg" 又如 "png"
// response API服务器的JSON输出将被还原成该结构体
//
// 当出现异常时输出非nil错误
func (weibo *Weibo) Upload(token string, params Params, reader io.Reader, imageFormat string, response interface{}) error {
apiUri := fmt.Sprintf("%s/%s/%s%s", ApiDomain, ApiVersion, UploadAPIName, ApiNamePostfix)
return weibo.sendPostHttpRequest(apiUri, token, params, reader, imageFormat, response)
}
// 向微博API服务器发送GET请求
func (weibo *Weibo) sendGetHttpRequest(uri string, token string, params Params, response interface{}) error {
// 生成请求URI
var uriBuffer bytes.Buffer
uriBuffer.WriteString(fmt.Sprintf("%s?access_token=%s", uri, token))
for k, v := range params {
value := fmt.Sprint(v)
if k != "" && value != "" {
uriBuffer.WriteString(fmt.Sprintf("&%s=%s", k, value))
}
}
requestUri := uriBuffer.String()
// 发送GET请求
resp, err := weibo.httpClient.Get(requestUri)
if err != nil {
return err
}
defer resp.Body.Close()
// 解析API服务器返回内容
bytes, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode == 200 {
err := json.Unmarshal(bytes, &response)
if err != nil {
return err
}
return nil
} else {
var weiboErr WeiboError
err := json.Unmarshal(bytes, &weiboErr)
if err != nil {
return err
}
return weiboErr
}
return nil
}
// 向微博API服务器发送POST请求
//
// 输入参数的含义请见Upload函数注释。当reader == nil时使用query string模式,否则使用multipart。
func (weibo *Weibo) sendPostHttpRequest(uri string, token string, params Params, reader io.Reader, imageFormat string, response interface{}) error {
// 生成POST请求URI
requestUri := fmt.Sprintf("%s?access_token=%s", uri, token)
// 生成POST内容
var bodyBuffer bytes.Buffer
var writer *multipart.Writer
if reader == nil {
// reader为nil时无文件上传,因此POST body为简单的query string模式
pb := url.Values{}
pb.Add("access_token", token)
for k, v := range params {
value := fmt.Sprint(v)
if k != "" && value != "" {
pb.Add(k, value)
}
}
bodyBuffer = *bytes.NewBufferString(pb.Encode())
} else {
// 否则POST body使用multipart模式
writer = multipart.NewWriter(&bodyBuffer)
imagePartWriter, _ := writer.CreateFormFile("pic", "image."+imageFormat)
io.Copy(imagePartWriter, reader)
for k, v := range params {
value := fmt.Sprint(v)
if k != "" && value != "" {
writer.WriteField(k, value)
}
}
writer.Close()
}
// 生成POST请求
req, err := http.NewRequest("POST", requestUri, &bodyBuffer)
if err != nil {
return err
}
if reader == nil {
// reader为nil时使用一般的内容类型
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
} else {
// 否则使用带boundary的multipart类型
req.Header.Set("Content-Type", writer.FormDataContentType())
}
// 发送请求
resp, err := weibo.httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
// 解析API服务器返回内容
bytes, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode == 200 {
err := json.Unmarshal(bytes, &response)
if err != nil {
return err
}
return nil
} else {
var weiboErr WeiboError
err := json.Unmarshal(bytes, &weiboErr)
if err != nil {
return err
}
return weiboErr
}
return nil
}