api - 从Twitter客户端读取响应返回错误

标签 api go twitter response

我正在尝试制作一个调用twitter搜索API的函数(使用dghubble/go-twitter)
但是,当我尝试从该API读取响应时,我得到了http2: response body closed这是我的代码:

func SearchTweets(query string) string {
    config := oauth1.NewConfig("consumer_key", "consumer_secret")
    token := oauth1.NewToken("access_token", "token_secret")
    httpClient := config.Client(oauth1.NoContext, token)

    // Twitter client
    client := twitter.NewClient(httpClient)

    // Search Tweets
    _ , resp, err := client.Search.Tweets(&twitter.SearchTweetParams{
        Query: "elon",
        Count: 50,
    })

    
    if err != nil {
        return err.Error()
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return err.Error()
    }
    return string(body)
}

最佳答案

此答复中引用的行号和文件是在回答之日记录的,因此不能保证它们永远正确无误。
dghubble's go-twitter search.go的第62行中,您正在调用的client.Search.Tweets()函数:

resp, err := s.sling.New().Get("tweets.json").QueryStruct(params).Receive(search, apiError)
请注意,它使用sling包构造和发送http请求,以及接收和解析http(JSON)响应。它所引用的sling包可以在here中找到。
具体来说,请密切注意sling.go。在第366行上,有一条注释指出:“接收是调用请求和执行的简写。”
Request()行上找到的280函数仅根据*http.Request对象的属性构造一个Sling。它返回所述请求以及错误(签名为func (s *Sling) Request() (*http.Request, error))Do()函数是关键部分。它执行作为第一个参数传递的http请求,尝试将(JSON)响应解析为提供的第二个参数(一个interface {},它应指向您希望将响应解析为的对象),并同时尝试解析提供给第三个参数的任何错误。毕竟,它关闭了响应主体。 具体来说,注意第385和386行:
// when err is nil, resp contains a non-nil resp.Body which must be closed
defer resp.Body.Close()
换句话说,响应主体在它进入go-twitter Tweets()范围之前就已关闭,因此您肯定无法最终读取该主体。毕竟,这些库的要点是为您省去了读取和解析响应正文等内容的麻烦。
通常,您应该能够使用提供的软件包获得所需的信息。具体来说,Tweets()函数具有以下签名:func (s *SearchService) Tweets(params *SearchTweetParams) (*Search, *http.Response, error)。请注意,第一个返回值的类型为*Search。这是从Receive()以及Do()函数读取的对象。它应该在关闭之前保存*http.Response主体中的所有信息:
search , resp, err := client.Search.Tweets(&twitter.SearchTweetParams{
    Query: "elon",
    Count: 50,
})
search对象的类型为*Search,其定义可以在here中找到。它包括状态的一部分(Tweet结构)以及一些元数据。您还可能会发现here,这对Tweet结构的定义很有帮助。
最后,如果出于某种原因您确实需要自己处理请求主体,则必须从头开始执行请求,这无论如何都会破坏go-twittersling库的目的。您可以在sling的基础上构建一些请求,但它不是很漂亮(实际上,从头开始构建请求也可能更干净)。不过,这是一个(未经测试的)示例,它是通过引用本文前面提到的链接以及this one编写的代码:
func MyTweetsFunc(httpClient *http.Client, requestBuilder *sling.Sling, params *twitter.SearchTweetParams) 
{
    // Use sling's Request() to construct the request, just as Receive() does
    req, err := requestBuilder.New().Get("tweets.json").QueryStruct(params).Request()
    if err != nil {
        // handle the error
    }
    
    // Get the response through the httpClient, since a sling client would parse and close the body automatically.
    resp, err := httpClient.Do(req)
    
    if err != nil {
        // handle the error
    }

    // Now you can do whatever you want with resp, which is simply an *http.Response. Its body is open for reading.
}
requestBuilder可以这样构造:
const twitterAPI = "https://api.twitter.com/1.1/"

requestBuilder := sling.New().Client(httpClient).Base(twitterAPI)
您通常将httpClient传递给twitter.NewClient()的客户端

关于api - 从Twitter客户端读取响应返回错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63267744/

相关文章:

iOS 关闭 iPad 屏幕

node.js - 通用术语的上下文

sockets - 如何为 Go gRPC 设置 SO_TIMEOUT

go - 没有方法的多态性

go - 如何在Go中对多个网址进行长轮询?

html - 使用 bootstrap 以表格形式显示表单

api - 测试调用相同私有(private)方法的多个公共(public)方法

php - 如何在 Laravel 5.5 中将数组作为 API 资源返回

iphone - Sharekit 还能用吗?

将 Twitter created_at 显示为 xxxx 前的 JavaScript 代码