使用绝对URL在请求URL中进行HTTP请求。

huangapple go评论71阅读模式
英文:

Make HTTP Request with an absolute URL in the Request URL

问题

我想知道是否可以使用Go的net/http库来发送以下请求:

GET http://test2.com/thisisatest HTTP/1.1
Host: test1.com

为了澄清,如果我发送请求到本地主机,我不想改变主机头,就像这样:

nc -lnvp 8001
listening on [any] 8001 ...
connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 55122
GET /headers HTTP/1.1
Host: not-localhost
User-Agent: Go-http-client/1.1
Content-Type: application/json
Accept-Encoding: gzip

但是我想要在请求行中包含完整的URL:

nc -lnvp 8001
listening on [any] 8001 ...
connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 55122
GET http://localhost/headers HTTP/1.1
Host: localhost
User-Agent: Go-http-client/1.1
Content-Type: application/json
Accept-Encoding: gzip

我似乎找不到任何相关信息。如果使用net/http不可能实现,是否有其他方法可以实现这个目标?

谢谢!

Diego

英文:

I was wondering if it's possible to make a request as follows using Go's net/http library:

GET http://test2.com/thisisatest HTTP/1.1
Host: test1.com

To clarify, if I'm sending a request to localhost I don't want to change the host header as in:

nc -lnvp 8001
listening on [any] 8001 ...
connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 55122
GET /headers HTTP/1.1
Host: not-localhost
User-Agent: Go-http-client/1.1
Content-Type: application/json
Accept-Encoding: gzip

But what I intend is to have the full URL in the request line:

nc -lnvp 8001
listening on [any] 8001 ...
connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 55122
GET http://localhost/headers HTTP/1.1
Host: localhost
User-Agent: Go-http-client/1.1
Content-Type: application/json
Accept-Encoding: gzip

I can't seem to find any information about it. If it's not possible using net/http is there any other way that this would be doable?

Thank you!

Diego

答案1

得分: 2

从https://pkg.go.dev/net/http#Request.Host,

对于客户端请求,Host可选地覆盖要发送的Host标头。如果为空,Request.Write方法将使用URL.Host的值。Host可能包含国际域名。

因此,您应该能够构建您的请求,将其Host字段设置为您想要的任何内容,然后进行请求。

考虑以下代码。在Playground上无法运行(不允许外部连接),但应该在您的工作站上运行。

package main

import (
	"io"
	"net/http"
	"os"
)

func main() {
	client := &http.Client{}
	req, err := http.NewRequest("GET", "https://httpbin.org/headers", nil)
	if err != nil {
		panic(err)
	}
	req.Host = "myserver.com"
	req.Header.Add("Content-Type", `application/json`)
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	} else if _, err := io.Copy(os.Stdout, resp.Body); err != nil {
		panic(err)
	}
}

https://httpbin.org/headers返回与请求一起发送的标头,因此这是一种验证此方法是否有效的有用方式。我的结果:

{
  "headers": {
    "Accept-Encoding": "gzip",
    "Content-Type": "application/json",
    "Host": "myserver.com",
    "User-Agent": "Go-http-client/2.0",
    "X-Amzn-Trace-Id": "Root=1-6217a78b-27317e7e06a097cb293b5db1"
  }
}

如您所见,由于我设置了请求的Host,http库没有从URL中设置它。

在这种情况下,httpbin请求处理程序不介意请求标头与URL不匹配。其他网站可能会在主机标头不匹配时返回400 Bad Request

请注意,您不能通过直接操作Host标头来实现相同的效果。您必须使用Request.Host

英文:

From https://pkg.go.dev/net/http#Request.Host,

// For client requests, Host optionally overrides the Host
// header to send. If empty, the Request.Write method uses
// the value of URL.Host. Host may contain an international
// domain name.

So you should be able to craft your request, set it's Host field to whatever you desire, and then make the request.

Consider the following code. It doesn't work on the Playground (which won't allow external connections) but should work on your workstation.

package main

import (
	"io"
	"net/http"
	"os"
)

func main() {
	client := &http.Client{}
	req, err := http.NewRequest("GET", "https://httpbin.org/headers", nil)
	if err != nil {
		panic(err)
	}
	req.Host = "myserver.com"
	req.Header.Add("Content-Type", `application/json`)
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	} else if _, err := io.Copy(os.Stdout, resp.Body); err != nil {
		panic(err)
	}
}

https://httpbin.org/headers returns the headers sent with a request, so it is a useful way to verify this works. My results:

{
  "headers": {
    "Accept-Encoding": "gzip",
    "Content-Type": "application/json",
    "Host": "myserver.com",
    "User-Agent": "Go-http-client/2.0",
    "X-Amzn-Trace-Id": "Root=1-6217a78b-27317e7e06a097cb293b5db1"
  }
}

As you can see, since I set the request Host, the http library didn't set it from the URL.

In this case, httpbin request handler doesn't mind that the request header doesn't match the url. Other sites might return a 400 Bad Request if the host header does not match.

Note that you cannot achieve the same by maniuplating a Host header directly. You must use Request.Host.

答案2

得分: 1

不,使用net/http是无法实现的,因为net/http实现的是HTTP协议,而你想要做的并不是HTTP。

如果使用net/http不可能实现,那么还有其他方法可以实现吗?

可以使用原始网络编程,即使用net包。

这是错误的。抱歉。

英文:

No, this us undoable with net/http because net/http implements HTTP and what you want to do simply isn't HTTP.

> If it's not possible using net/http is there any other way that this would be doable?

Do raw networking, i.e. use package net.

This is wrong. Sorry.

huangapple
  • 本文由 发表于 2022年2月24日 22:58:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/71253939.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定