【问题标题】:How to use two client.Do use golang如何使用两个客户端。请使用 golang
【发布时间】:2018-04-25 21:06:22
【问题描述】:

我使用 go package net/http,我想发布到登录 url,然后获取节点页面 我想使用两次 client.Do 因为 cookie 这是我的代码

package main

import (
    "log"
    "net/http"
    "net/http/cookiejar"
    "net/url"
)

func main() {
    cookieJar, _ := cookiejar.New(nil)
    client := &http.Client{
        Jar: cookieJar,
    }

    loginUrl, _ := url.Parse("https://pro.v2bz.com/auth/login")

    v := url.Values{}
    v.Add("email", "1231231231@qq.com")
    v.Add("passwd", "1231231231")

    req := &http.Request{
        Method:   "POST",
        URL:      loginUrl,
        PostForm: v,
    }
    resp, err := client.Do(req)
    if err != nil {
        log.Println("login failed", err)
    }
    defer resp.Body.Close()
    log.Println(resp.Status)

    nodeUrl, _ := url.Parse("https://pro.v2bz.com/user/node")
    nodeReq := &http.Request{
        Method: "GET",
        URL:    nodeUrl,
    }

    nodeResp, err := client.Do(nodeReq)
    if err != nil {
        log.Println("node request failed", err)
    }
    log.Println(nodeResp.Status)
}

但是我得到了这个错误 恐慌:分配给 nil 映射中的条目 如何在一个代码中使用两次 client.Do?

【问题讨论】:

  • 不要只打印错误并继续——如果出现错误,http.Response 将无法使用。
  • 也停止忽略错误。该代码中有 3 个地方将错误返回值转储到下划线中。检查错误,你不能只是假设一切都成功。如果它返回错误,那是因为该函数可能会失败。恐慌堆栈跟踪将准确指定代码中发生故障的位置。
  • 让我印象深刻的一件事是您正在创建一个 http.Request 作为文字。 Request 结构有一个映射 Header,您没有初始化它。请改用 http.NewRequest()。
  • 指出引用代码的哪一行导致引用错误会很有帮助。
  • 第二个 client.Do 中的恐慌。如果我不使用 cookie 我没问题,但我无法保留 cokies。

标签: go cookies client


【解决方案1】:

request.go 中发生错误(第 389 行):

// AddCookie adds a cookie to the request. Per RFC 6265 section 5.4,
// AddCookie does not attach more than one Cookie header field. That
// means all cookies, if any, are written into the same line,
// separated by semicolon.
func (r *Request) AddCookie(c *Cookie) {
    ...
    if c := r.Header.Get("Cookie"); c != "" {
        r.Header.Set("Cookie", c+"; "+s)
    } else {
        r.Header.Set("Cookie", s)
    }
}

看到该请求尝试设置 Header。如果你制作标题,将工作。

nodeReq := &http.Request{
    Method: "GET",
    URL:    nodeUrl,
    TLS:    resp.TLS,
    Header: make(Header),
}

适当的方法是http.NewRequest。 链接:https://golang.org/pkg/net/http/#NewRequest

在 http.NewRequest (request.go line 778) 中,Header 的创建方式如下:

req := &Request{
    Method:     method,
    URL:        u,
    Proto:      "HTTP/1.1",
    ProtoMajor: 1,
    ProtoMinor: 1,
    Header:     make(Header),
    Body:       rc,
    Host:       u.Host,
}

另请参阅,如果您使用 HTTP,非 HTTPS,标头不是必需的,也可以工作!

【讨论】:

  • 如果我使用 https 如何保存 cookie?
  • @YuanmengXiao,https 中的cookies 相当于http。一种方法是 req.Header["cookie"]=[]string{"cookie data"}.
  • @YuanmengXiao,如果 cookie 与 resp.Cookies 相同,则 nodeReq.AddCookie(resp.Cookies()[0])(在您的代码中)
【解决方案2】:

错误不是因为您使用了两次client.Do。事实上,您可以多次调用它。错误消息表明在某处访问了一个未分配的变量(map)。在您的情况下,导致错误的变量是Request.Header。使用适当的方法来构造请求,例如http.NewRequest:

nodeReq, err := http.NewRequest("GET", nodeUrl, nil)

发送表单内容的POST请求时,使用Client.PostForm,例如

resp, err := client.PostForm(loginUrl, v)

此方法将设置适当的Content-Type 标头,然后调用client.Do

【讨论】:

  • 我想自己定义请求,但不想使用 http.NewRequestclient.PostForm
【解决方案3】:

恐慌是因为 Request.Header 没有初始化,在第二个 Client.Do cookie 无法添加到 Request.Header (节点请求)。 In this link i learn how to add header by my self 一种解决方案是

v := url.Values{}
v.Add("email", "1231231231@qq.com")
v.Add("passwd", "1231231231")

req, err := http.NewRequest("POST", "https://pro.v2bz.com/auth/login", strings.NewReader(v.Encode()))
req.PostForm = v
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

在第二个请求时,@aristofanio-garcia 说使用

nodeReq := &http.Request{
    Method: "GET",
    URL:    nodeUrl,
    Header: make(http.Header), //add this to initialize Request.Header so the cookies could add into header
}

【讨论】:

    猜你喜欢
    • 2021-07-20
    • 2018-04-27
    • 2016-10-30
    • 1970-01-01
    • 1970-01-01
    • 2017-10-04
    • 2021-06-23
    • 1970-01-01
    • 2011-02-03
    相关资源
    最近更新 更多