unknwon/the-way-to-go_ZH_CN · error

expected GET

Error message

expected GET

What it means

Error from the closure-based validation in the eBook's httpRequestHandler example (16.10.2): the anonymous func checks req.Method != "GET" first and returns errors.New("expected GET") for any other verb; the outer code turns it into a 400 via w.WriteHeader(400) and io.WriteString(w, err). The snippet demonstrates concentrating all request validation in one closure so the handler body stays clean.

Solutions

  1. Fix the client to use GET if the operation is a read: fetch(url) defaults to GET — remove method: 'POST'; drop curl -d
  2. If other verbs are legitimate, return 405 Method Not Allowed with an Allow header instead of a bare 400 — 405 is the correct status for a wrong verb
  3. Route by verb so the handler is never reached with the wrong method: Go 1.22+ net/http mux patterns like mux.HandleFunc("GET /path", h)
  4. Compare against the http.MethodGet constant instead of the literal "GET" to avoid typo class bugs

Example fix

// before (inside the closure)
if req.Method != "GET" {
	return errors.New("expected GET")
}
// ...
if err != nil {
	w.WriteHeader(400)
	io.WriteString(w, err)
	return
}

// 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

// register the handler so only GET reaches it (Go 1.22+ method patterns)
mux.HandleFunc("GET /command", httpRequestHandler)

Try / catch

err := func() error {
	if req.Method != http.MethodGet {
		return errors.New("expected GET")
	}
	// further checks...
	return nil
}()
if err != nil {
	http.Error(w, err.Error(), http.StatusBadRequest)
	return
}

Prevention

When it happens

Trigger: Any non-GET request reaching this handler: POST/PUT/DELETE from a form submission, a CORS preflight OPTIONS, or curl defaulting to POST when given -d. The method check runs before parseInput, so a wrong verb always fails here even with a valid body.

Common situations: Front-end switched to fetch with method POST while the backend still demands GET; health-checkers and proxies sending HEAD; browser CORS preflight OPTIONS hitting the route; copy-pasting the book handler without aligning the allowed method with the client.

Related errors


AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15). Data as JSON: /api/errors/fcf6693d55ba6e41. Report an issue: GitHub.

Appendix: source

Thrown at eBook/16.10.md:50

... err1 := api.Func1()
if err1 != nil {
    fmt.Println("err: " + err.Error())
    return
}
err2 := api.Func2()
if err2 != nil {
...
    return
}    
```

首先,包括在一个初始化的 `if` 语句中对函数的调用。但即使代码中到处都是以 `if` 语句的形式通知错误(通过打印错误信息)。通过这种方式,很难分辨什么是正常的程序逻辑,什么是错误检测或错误通知。还需注意的是,大部分代码都是致力于错误的检测。通常解决此问题的好办法是尽可能以闭包的形式封装你的错误检测,例如下面的代码:

```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() ...
```

这种方法可以很容易分辨出错误检测、错误通知和正常的程序逻辑(更详细的方式参考[第 13.5 小节](13.5.md))。

**在开始阅读[第 17 章](17.0.md)前,先回答下列 2 个问题:**

View on GitHub (pinned to 7a54d34d36)