Golang中HTTP错误代码400的原因和解决方法
Golang中HTTP错误代码400的原因和解决方法 我过去曾成功发出过许多请求,但通常是发给我自己的网络服务器。这次我被卡住了。这个请求在 Postman 中工作正常,但在我的 Go 代码中,服务器返回了 400 错误码。我希望响应能给我一些线索,告诉我需要修改什么。
在 Postman 中,我将主机设置为:
https://finnhub.io/api/v1
然后在 URL 行添加了:
/stock/candle,并将其设置为 ‘get’。我设置了参数,URL 随后显示为:
{{host}}/stock/candle?symbol=msft&resolution=D&from=1649887189&to=1658527189
授权信息在集合中设置为: 键:X-Finnhub-Token 值:c362xxxxxxxxxuojg (已为安全考虑修改) 我点击发送,它按请求执行。我得到了一系列股票蜡烛图数据。很好。
然而,当我在 Go 中尝试这样做时,我得到了 400 错误。
urlString := fmt.Sprintf("https://finnhub.io/api/v1" + "/stock/candle")
req, err := http.NewRequest("get", urlString, nil)
values := req.URL.Query()
values.Add("symbol", specification.Stock.Symbol)
if specification.TriggerCriteria.FrequencyUnit == data.UnitDay {
values.Add("resolution", "D")
}
now := time.Now()
nowString := fmt.Sprintf("%v", now.Unix())
oneHundredDaysAgo := time.Hour * 24 * 100 * -1
past := now.Add(oneHundredDaysAgo)
pastString := fmt.Sprintf("%v", past.Unix())
values.Add("from", pastString)
values.Add("to", nowString)
req.URL.RawQuery = values.Encode()
req.Header.Add("X-Finnhub-Token", "c362jxxxxxxx0uojg")
resp, err := http.DefaultClient.Do(req)`
响应状态码为 400。
请求截图:

更多关于Golang中HTTP错误代码400的原因和解决方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我正在使用 Goland 作为我的 IDE。我可以查看任何变量,但我找不到任何问题。
我希望能从响应中得到一些线索,告诉我需要修改什么。
是否有可以查看的“控制台”(网络浏览器)?它是否抱怨CORS或类似的问题?
我怀疑你是对的。我可能提供了一个无效的 to 参数,因为我当时正在学习那个 API。
仅凭400响应很难判断问题所在。
能否打印出resp.Body的内容,这可能会给你更多线索。
例如:
io.Copy(os.Stdout, res.Body)
也许可以贴出一些完整的可运行代码,这样我们就能看到发生了什么……
Sibert:
httputil.DumpResponse
我刚刚再次运行了有问题的代码来检查转储的响应。这次它成功了,状态码是200。而且我并没有修改代码。这相当奇怪,但我需要继续推进。我会使用SDK,因为它每次都能正常工作。 感谢您的回复。
我尚未查明为何会收到错误代码 400。不过,我已经下载了 Finnhub 的 Go SDK,它可以正常获取数据。这是一个非常复杂的项目,访问层级很高,我还没找到他们具体在哪里执行请求。我想我会使用这个 SDK。但我仍然想知道,为什么我能在 Postman 中使用这个请求,却无法在 Go 中作为一个简单的请求使用。
我还没弄明白为什么会出现错误代码400。
服务器的响应是什么?类似 dump, err := httputil.DumpResponse 这样的吗?
你说响应是空的,但如果你能从服务器获得响应,可能会找到线索。服务器必须以某种方式响应。我曾经用AJAX玩过一些API,遇到过不少CORS错误。
有趣。 除了以下几行代码外,程序每次都会发送相同的请求:
fmt.Sprintf("%v", now.Unix())
这几行代码每次运行都会变化。(from 参数也是如此。)
会不会是服务器对某些值有异议?
例如,服务器会拒绝未来的 to 值吗?
这会不会是客户端和服务器之间的时钟偏差问题?
如果在请求中省略 to= 参数会怎么样?
我逐步查看了他们的代码,他们的请求看起来和我的完全一样。
SDK:
GET /api/v1/stock/candle?from=1649970549&resolution=D&symbol=AAPL&to=1658610549 HTTP/1.1
Host: finnhub.io
User-Agent: OpenAPI-Generator/2.0.13/go
Accept: application/json
X-Finnhub-Token: cbbb00iad3ibhoa1vbcg
Accept-Encoding: gzip
Mine:
GET /api/v1/stock/candle?from=1649970549&resolution=D&symbol=AAPL&to=1658610549 HTTP/1.1
Host: finnhub.io
User-Agent: OpenAPI-Generator/2.0.13/go
Accept: application/json
X-Finnhub-Token: cbbb00iad3ibhoa1vbcg
Accept-Encoding: gzip
我是使用以下方法创建这些请求的:
httputil.DumpRequestOut
问题出在查询参数的编码上。你在创建请求后修改了req.URL.Query(),但http.NewRequest已经解析了URL,而后续对req.URL.Query()的修改没有正确应用到请求上。正确的做法是在创建请求前构建完整的URL,或者使用url.Values直接设置RawQuery。
以下是修正后的代码:
package main
import (
"fmt"
"net/http"
"net/url"
"time"
)
func main() {
baseURL := "https://finnhub.io/api/v1/stock/candle"
// 创建查询参数
values := url.Values{}
values.Add("symbol", "msft")
values.Add("resolution", "D")
now := time.Now()
oneHundredDaysAgo := now.Add(-100 * 24 * time.Hour)
values.Add("from", fmt.Sprintf("%d", oneHundredDaysAgo.Unix()))
values.Add("to", fmt.Sprintf("%d", now.Unix()))
// 构建完整URL
fullURL := fmt.Sprintf("%s?%s", baseURL, values.Encode())
req, err := http.NewRequest("GET", fullURL, nil)
if err != nil {
panic(err)
}
req.Header.Add("X-Finnhub-Token", "c362xxxxxxxxxuojg")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Printf("Status Code: %d\n", resp.StatusCode)
}
或者使用req.URL.RawQuery的替代方案:
package main
import (
"fmt"
"net/http"
"net/url"
"time"
)
func main() {
baseURL := "https://finnhub.io/api/v1/stock/candle"
req, err := http.NewRequest("GET", baseURL, nil)
if err != nil {
panic(err)
}
// 直接设置RawQuery
values := url.Values{}
values.Add("symbol", "msft")
values.Add("resolution", "D")
now := time.Now()
oneHundredDaysAgo := now.Add(-100 * 24 * time.Hour)
values.Add("from", fmt.Sprintf("%d", oneHundredDaysAgo.Unix()))
values.Add("to", fmt.Sprintf("%d", now.Unix()))
req.URL.RawQuery = values.Encode()
req.Header.Add("X-Finnhub-Token", "c362xxxxxxxxxuojg")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Printf("Status Code: %d\n", resp.StatusCode)
}
关键点:
- 使用
url.Values{}而不是req.URL.Query()来构建查询参数 - 确保在创建请求前或通过
RawQuery设置完整的查询字符串 - HTTP方法应该使用大写的"GET"
这两种方法都能确保查询参数正确编码并包含在请求中,从而避免400错误。


