首页 > 解决方案 > 使用一系列处理程序停止 HTTP 调用并返回错误;可能吗?

问题描述

使用以下代码(取自https://gist.github.com/miku/293f253b706c4de1b75c):

package main

import (
    "bytes"
    "encoding/json"
    "io"
    "io/ioutil"
    "log"
    "net/http"
)

type Payload struct {
    Name     string
    Location string
}

func readSecond(w http.ResponseWriter, r *http.Request) {
    log.Println("entering readSecond")

    // r.Body is a io.ReadCloser, that's all we know
    b, err := ioutil.ReadAll(r.Body)
    if err != nil {
        log.Fatal(err)
    }

    // closing a NopCloser won't hurt anybody
    defer r.Body.Close()

    log.Printf("request body: %s", string(b))
}

func readFirst(w http.ResponseWriter, r *http.Request) {
    log.Println("entering readFirst")

    // temporary buffer
    b := bytes.NewBuffer(make([]byte, 0))

    // TeeReader returns a Reader that writes to b what it reads from r.Body.
    reader := io.TeeReader(r.Body, b)

    // some business logic
    var payload Payload
    if err := json.NewDecoder(reader).Decode(&payload); err != nil {
        log.Fatal(err)
    }

    // we are done with body
    defer r.Body.Close()

    log.Printf("deserialized payload from body: %v", payload)

    // NopCloser returns a ReadCloser with a no-op Close method wrapping the provided Reader r.
    r.Body = ioutil.NopCloser(b)
}

func handler(w http.ResponseWriter, r *http.Request) {
    readFirst(w, r)
    readSecond(w, r)
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

有没有办法阻止 readSecond()(第二个处理程序)运行?

例子:

如果payload == ""我想退出 HTTP 调用并返回错误。

有没有办法用这段代码做到这一点?

我知道我可以使用嵌套中间件来做到这一点。但是像这样的处理程序呢?

标签: gohandlermiddleware

解决方案


使用方法和接收器有助于更好地控制错误。您不能在 http 的处理程序中定期返回错误。

package main

import (
    "bytes"
    "encoding/json"
    "io"
    "io/ioutil"
    "log"
    "net/http"
)

type Payload struct {
    Name     string
    Location string
}

type Handle struct {
    err error
}

func (h *Handle) readSecond(w http.ResponseWriter, r *http.Request) {
    log.Println("entering readSecond")

    // r.Body is a io.ReadCloser, that's all we know
    b, err := ioutil.ReadAll(r.Body)
    if err != nil {
        log.Fatal(err)
    }

    // closing a NopCloser won't hurt anybody
    defer r.Body.Close()

    log.Printf("request body: %s", string(b))
}

func (h *Handle) readFirst(w http.ResponseWriter, r *http.Request) {
    log.Println("entering readFirst")
    h.err = nil

    // temporary buffer
    b := bytes.NewBuffer(make([]byte, 0))

    // TeeReader returns a Reader that writes to b what it reads from r.Body.
    reader := io.TeeReader(r.Body, b)

    // some business logic
    var payload Payload
    if err := json.NewDecoder(reader).Decode(&payload); err != nil {
        // log.Fatal("read first", err)
        h.err = err
        w.Write([]byte(err.Error()))
    }

    // we are done with body
    defer r.Body.Close()

    log.Printf("deserialized payload from body: %v", payload)

    // NopCloser returns a ReadCloser with a no-op Close method wrapping the provided Reader r.
    r.Body = ioutil.NopCloser(b)
}

func handler(w http.ResponseWriter, r *http.Request) {
    var handle Handle
    handle.readFirst(w, r)
    if handle.err == nil {
        handle.readSecond(w, r)
    }
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

推荐阅读