unknwon/the-way-to-go_ZH_CN · error
expected GET
Error message
expected GET
What it means
Quoted duplicate of the 16.10.2 handler example inside Discussion_about_16.10.md, the reader-notes file debating when the closure-based error-checking style is appropriate. Runtime meaning is identical to the original: the validation closure rejects any request whose method is not GET with errors.New("expected GET"), and the outer handler answers with HTTP 400. The discussion argues the pattern suits business-rule violations more than general error handling.
Source
Thrown at eBook/Discussion_about_16.10.md:50
2、在其他语言中,我们可能会用到 try... catch...语句来对可能出现的错误进行处理,难道你会说try-catch语句让你的代码一团糟,程序逻辑和错误处理混在一起很复杂,让你阅读代码困难么。绝大多数情况下,让你感觉难以阅读甚至恶心(可能形容过度了)的代码绝不会是因为错误处理相关的代码导致的,而是当时写这些代码的人逻辑不清甚至逻辑混乱造成的。
3、这个可能和每个人的习惯(自己写代码的思路、风格)或者说适应(看其他人的代码时能很快习惯作者的代码风格)有关,我每次看代码都会先略过错误处理的部分,那么剩下的就是理想情况下的程序逻辑了,如果对某一处心存疑惑那么就再仔细看这部分的代码。毕竟我们写的代码绝大多数情况下是希望它按理想的情况跑的,
_ _ _
### 关于16.10.2的第二个代码示例
16.10.2小结中关于错误处理的第二个代码示例是推荐给我们的错误处理方式,对于其推荐的这种方式,个人认为是有一定的适用范围的,并不适合大多数的错误处理,反而在处理某些业务逻辑时可以使用,比如将不符合业务逻辑的情况视作一种错误(自定义)来统一做处理。
**书中代码示例二**:
```Go
func httpRequestHandler(w http.ResponseWriter, req *http.Request) {
err := func () error {
if req.Method != "GET" {
return errors.New("expected GET")
}
if input := parseInput(req); input != "command" {
return errors.New("malformed command")
}
// 可以在此进行其他的错误检测
} ()
if err != nil {
w.WriteHeader(400)
io.WriteString(w, err)
return
}
doSomething() ...
```
1、代码示例二中对不符合业务逻辑的两种情况做了归类,并自定义了错误,做了统一的处理。这样从业务层面来看,将不符合业务逻辑的情况视为错误,统一写到了匿名函数中,剩下了一个统一的错误处理与正常的业务逻辑。或许采用这种方式处理这类场景还不错,但是如果换作下面的这个示例可能就不是很合理了。
下面的示例一是采用了作者推荐的统一处理错误方式,示例二使用的是通常的错误处理方式View on GitHub (pinned to 7a54d34d36)
Solutions
- Align the client with the handler: use GET for reads (plain fetch(url), curl without -d)
- Return 405 + Allow header instead of 400 when the verb is wrong — that is the semantically correct status
- Route by verb with Go 1.22+ mux patterns ("GET /path") so wrong-method requests never enter the closure
- Compare with the http.MethodGet constant rather than the literal "GET"
Example fix
// before
if req.Method != "GET" {
return errors.New("expected GET")
}
// after
if req.Method != http.MethodGet {
w.Header().Set("Allow", http.MethodGet)
w.WriteHeader(http.StatusMethodNotAllowed)
io.WriteString(w, "expected GET")
return nil
} Defensive patterns
Strategy: validation
Validate before calling
// route by verb so the closure never sees a wrong method
mux.HandleFunc("GET /command", httpRequestHandler) Try / catch
if req.Method != http.MethodGet {
w.Header().Set("Allow", http.MethodGet)
w.WriteHeader(http.StatusMethodNotAllowed)
io.WriteString(w, "expected GET")
return
} Prevention
- Compare with http.MethodGet, not the literal "GET"
- Use 405 + Allow for wrong verbs; 400 only for malformed payloads
- Check what verb the client actually sends after every front-end change; curl -d silently switches to POST
- Handle OPTIONS/HEAD explicitly if proxies or health-checkers hit the endpoint
When it happens
Trigger: A non-GET request (POST, PUT, DELETE, OPTIONS preflight, or curl -d which defaults to POST) reaching a handler built from this snippet; the closure's first check fails before parseInput ever runs.
Common situations: Same as the chapter version: client switched verbs after an API change, health-checkers sending HEAD, CORS preflights. Additionally: copying from the discussion file instead of the chapter, so the code's line numbers differ when hunting the source of the 400.
Related errors
AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15).
Data as JSON: /api/errors/cdb9adecd52b4c4c.
Report an issue: GitHub.