如何自定义解析错误的HTTP 400响应?

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

How can I customize HTTP 400 responses for parse errors?

问题

我写了一个需要所有响应都是JSON格式的REST API服务。然而,当Go的HTTP请求解析器遇到错误时,它会返回一个纯文本的400响应,而不会调用我的处理程序。例如:

注意无效的Authorization头部。当然,400是正确的响应,但它是纯文本的。有没有办法配置Go的HTTP解析器来使用自定义的错误响应媒体类型和内容?

英文:

I've written a REST API service that requires that all responses be JSON. However, when the Go HTTP request parser encounters an error, it returns 400 as a plain text response without ever calling my handlers. Example:

> curl -i -H 'Authorization: Basic hi    
there' 'http://localhost:8080/test' -v
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> Authorization: Basic hi
> there
> 
< HTTP/1.1 400 Bad Request
HTTP/1.1 400 Bad Request
< Content-Type: text/plain; charset=utf-8
Content-Type: text/plain; charset=utf-8
< Connection: close
Connection: close

< 
* Closing connection 0

Note the invalid Authorization header. Of course 400 is the proper response, but it's text/plain, of course. Is there some way to configure the Go http parser to use custom error response media types and bodies?

答案1

得分: 6

你无法做到这一点。你可以在net/http源代码中找到这个问题,只有在请求格式错误时才会发生:

https://github.com/golang/go/blob/master/src/net/http/server.go#L1744

我认为你的问题可能是在curl中添加的头部中有一个换行符?

401、403、404、500错误可以用json进行响应,但是请求错误或者头部错误(太长或者格式错误)是在server.go中处理的。

目前还没有办法拦截这些错误,尽管正在考虑中,所以在go中你唯一的解决方案就是修补stdlib源代码(我不建议这样做)。然而,由于这个错误只会在客户端犯错并且请求格式错误时出现,所以可能不是一个很大的问题。文本响应的原因是为了让浏览器或类似的客户端(如没有使用-v选项的curl)不会看到一个空的响应。你可以在你的应用程序前面放一个像nginx这样的代理,但是你将永远看不到这个请求,因为它是一个错误的请求,你的代理会处理它。

也许你可以通过在前面放一个像nginx这样的代理来实现,如果你为它设置一个特定的静态错误页面来处理400错误,并提供一个你指定的400.json文件?这是我能想到的唯一解决方案。类似下面这样的nginx指令可能适用:

error_page 400 /400.json;

如果你想要自定义这些错误,也许可以在链接的问题中添加评论,让他们知道你遇到了这个特定的问题。

英文:

You can't. You can find this in net/http source, it only happens if the request was malformed:

https://github.com/golang/go/blob/master/src/net/http/server.go#L1744

I think your problem might be a new line in the header you're adding in curl?

401, 403, 404, 500 errors you'll be able to respond with json, but bad requests or bad headers (too long, malformed) are handled within server.go.

There is at present no way to intercept such errors though it is under consideration, so your only solution in go would be to patch the stdlib source (I don't recommend this). However, since this error only presents if the client has made a mistake and the request is malformed, it's probably not a huge problem. The reason for the text response is so that a browser or similar client (like curl without -v) doesn't just see an empty response. You could put a proxy like nginx in front of your app but then you'd never see the request either as it is a bad request, your proxy would handle it.

Possibly you'd be able to do it with a proxy like nginx in front though if you set a specific static error page for it to serve for 400 errors and serve a 400.json file that you specify? That's the only solution I can think of. A directive something like this might work for nginx:

error_page 400 /400.json;

If you'd like to be able to customise these errors, perhaps add a comment to the issue linked to let them know you had this specific problem.

答案2

得分: -2

如果你正在使用标准的net/http库,你可以使用以下代码。参考这个答案在标准http包中显示自定义404错误页面@Mostafa,我从中获取了这个示例。

func homeHandler(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/" {
        errorHandler(w, r, http.StatusNotFound)
        return
    }
    fmt.Fprint(w, "欢迎回家")
}

func errorHandler(w http.ResponseWriter, r *http.Request, status int) {
    w.WriteHeader(status)
    if status == http.StatusNotFound {
        // 在这里输出JSON
    }
}
英文:

If you are using the standard net/http library you can use the following code. Take a look at this answer Showing custom 404 error page with standard http package @Mostafa to which I got this example from

func homeHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		errorHandler(w, r, http.StatusNotFound)
		return
	}
	fmt.Fprint(w, "welcome home")
}

func errorHandler(w http.ResponseWriter, r *http.Request, status int) {
    w.WriteHeader(status)
    if status == http.StatusNotFound {
        // JSON Out here
    }
}

huangapple
  • 本文由 发表于 2017年8月22日 01:11:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/45802492.html
匿名

发表评论

匿名网友

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

确定