当我使用"net/http"获取一些图像时,为什么会出现"net/http:请求在等待连接时已取消"的错误?

6
我正在使用Go语言编写网络爬虫,用于收集互联网上的图片。我的爬虫大部分时间都能正常工作,但有时会因为某些原因无法获取图片。
以下是我的代码片段:
package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    var client http.Client
    var resp *http.Response

    // var imageUrl = "https://istack.dev59.com/tKsDb.webp"  // It works well
    var imageUrl = "https://precious.jp/mwimgs/b/1/-/img_b1ec6cf54ff3a4260fb77d3d3de918a5275780.jpg"  // It fails

    req, _ := http.NewRequest("GET", imageUrl, nil)
    req.Header.Add("User-Agent", "My Test")

    client.Timeout = 3 * time.Second
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println(err.Error())  // Fails here
        return
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        fmt.Printf("Failure: %d\n", resp.StatusCode)
    } else {
        fmt.Printf("Success: %d\n", resp.StatusCode)
    }

    fmt.Println("Done")
}

我的代码片段可以处理大多数URL(例如“https://istack.dev59.com/tKsDb.webp”),但是如果尝试获取“https://precious.jp/mwimgs/b/1/-/img_b1ec6cf54ff3a4260fb77d3d3de918a5275780.jpg”等URL,则无法工作。通过调用err.Error()给出的错误信息是:

获取https://precious.jp/mwimgs/b/1/-/img_b1ec6cf54ff3a4260fb77d3d3de918a5275780.jpg: net/http:请求取消(等待标头时超过了Client.Timeout)"

我的Go版本是"go1.9.3 darwin/amd64",我可以使用Google Chrome和curl命令获取图像,因此我不认为我的IP地址被阻止。除此之外,我已经将User-Agent更改为像真正的浏览器一样,但仍然没有运气。
我的代码有什么问题?还是"precious.jp"的管理员做了一些魔法来阻止我的访问?
1个回答

3

由于您正在使用 https,因此需要创建具有自定义传输方式的 http.Client 并配置 TLS(请参见 http.Transport),例如:

package main

import (
    "crypto/tls"
    "fmt"
    "net/http"
    "time"
)

func main() {
    //---------------------- Modification ----------------------
    //Configure TLS, etc.
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: true,
        },
    }
    client := &http.Client{
        Transport: tr,
        Timeout:   3 * time.Second,
    }
    //---------------------- End of Modification ----------------

    // var imageUrl = "https://istack.dev59.com/tKsDb.webp"  // It works well
    var imageUrl = "https://precious.jp/mwimgs/b/1/-/img_b1ec6cf54ff3a4260fb77d3d3de918a5275780.jpg" // It fails

    req, _ := http.NewRequest("GET", imageUrl, nil)
    req.Header.Add("User-Agent", "My Test")

    resp, err := client.Do(req)
    if err != nil {
        fmt.Println(err.Error()) // Fails here
        return
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        fmt.Printf("Failure: %d\n", resp.StatusCode)
    } else {
        fmt.Printf("Success: %d\n", resp.StatusCode)
    }

    fmt.Println("Done")
}

谢谢!顺便说一下,i.stack.imgur.com也是https。为什么该域名可以在没有TLSClientConfig的情况下工作?我已经使用https://cryptoreport.websecurity.symantec.com/checker/调查了SSL/TLS证书信息,但是我在`precious.jp`上没有发现任何可疑的东西。 - Sa Oh
我不确定原因是什么,但在检查请求时(使用 curl -v <IMG_URL>),来自 precious.jp 的响应中未设置 content-length 标头。顺便问一下,答案中的解决方案是否适用于您的情况?我已在我的机器上进行了测试,它可以正常工作。 - putu
是的,这在我的端上也可以工作。谢谢!但我仍然在想 InsecureSkipVerify: true 在这种情况下是否是个好主意。顺便说一句,我可以看到 precious.jpContent-Length - Sa Oh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接