【问题标题】:Can't get Go http to return an error; 'No data recieved'无法让 Go http 返回错误; '未收到数据'
【发布时间】:2016-04-16 10:42:00
【问题描述】:

我正在尝试使用 Go 构建一个基本 API,它使用 PostgreSQL library 返回 SQL 查询的结果。

目前我可以让程序返回值,但我无法让它向用户返回失败的消息,即一些带有错误消息的 JSON。

我有一个错误函数如下:

func handleError(w http.ResponseWriter, err error) {
    if err != nil {
        log.Print(err.Error() + "\r\n") // Logging
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}

然而,http.Error 方法似乎并没有返回任何东西。抛出的错误是数据库中不存在的表(该表被记录到文本文件中:即 2016/01/11 23:28:19 pq: 关系“building_roof”不存在

我的程序查询代码如下所示:

table := pq.QuoteIdentifier(table)
identifier := pq.QuoteIdentifier("ID")
rows, err := db.Query( fmt.Sprintf("SELECT %s, ST_AsText(geom) FROM %s WHERE %s = $1", identifier, table, identifier), feature)
handleError(w, err)

导致错误只会导致 Chrome 错误:

没有收到数据

ERR_EMPTY_RESPONSE

编辑完整代码:

package main

import (
    "fmt"
    "encoding/json"
    "os"
    "log"
    "net/http"
    "database/sql"
    "strings"
    "time"
    "github.com/lib/pq"
)


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

    f, err := os.OpenFile("pgdump_errorlog.txt", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
    log.Print("Couldn't open file")
    defer f.Close()
    log.SetOutput(f)

    // Timing
    start := time.Now()

    // Postgres Credentials
    const (
        DB_USER     = "postgres"
        DB_PASSWORD = "OMITTED" // Removed details !
        DB_PORT     = "OMITTED"
        DB_NAME     = "OMITTED"
    )

    // Postgres Connect
    dbinfo := fmt.Sprintf("user=%s password=%s dbname=%s port=%s sslmode=disable",
                           DB_USER, DB_PASSWORD, DB_NAME, DB_PORT)
    db, err := sql.Open("postgres", dbinfo)
    handleError(w, err)
    defer db.Close()

    table := r.FormValue("table")
    feature := r.FormValue("id")
    if table != "" {

        //Postgres Query
        var (
            id int
            geom string
        )

        table := pq.QuoteIdentifier(table)
        identifier := pq.QuoteIdentifier("ID")
        rows, qerr := db.Query( fmt.Sprintf("SELECT %s, ST_AsText(geom) FROM %s WHERE %s = $1", identifier, table, identifier), feature)
        handleError(w, err)
        defer rows.Close()
        for rows.Next() {
            err := rows.Scan(&id, &geom)
            handleError(w, err)
        }
        err = rows.Err()
        handleError(w, err)

        // Maniplate Strings
        returngeom := strings.Replace(geom, "1.#QNAN", "", -1)
        i := strings.Index(returngeom, "(")
        wkt := strings.TrimSpace(returngeom[:i])
        returngeom = returngeom[i:]

        type WTKJSON struct {
            WTKType   string
            Geometry  string
            Elapsed   time.Duration
        }

        returnjson := WTKJSON{Geometry:  returngeom, WTKType: wkt , Elapsed: time.Since(start)/1000000.0}
        json.NewEncoder(w).Encode(returnjson)

    }

}

func handleError(w http.ResponseWriter, err error) {
    if err != nil {
        log.Print(err.Error() + "\r\n") // Logging
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}


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

【问题讨论】:

  • 你能展示你的主要路线吗?
  • 如果你愿意,我已经留下了完整的代码供你剖析:)
  • 一些调试技巧:在 main 中设置一次日志输出,而不是在每次调用处理程序时设置它。对 handleError 的每次调用都应替换为 if err != nil { handleError(err); return }。记录调用 JSON 编码器返回的错误。
  • 不熟悉go,如果没有响应,则表示响应线程崩溃或挂起。如果同时出现 2 个破坏性请求,则“func handler”中的文件处理是一场灾难。您应该在“处理程序”中捕获任何错误,以便不会直接引发错误,并且在失败的情况下,它会冷响应客户端的响应。

标签: postgresql api go


【解决方案1】:

以下似乎允许我返回 JSON 错误:

func handleError(w http.ResponseWriter, err string) {
    type APIError struct {
        Error string
    }
    re, _ := json.Marshal(APIError{Error: err})
    io.WriteString(w, string(re))
}

这样使用:

rows, err := db.Query( fmt.Sprintf("SELECT %s, ST_AsText(geom) FROM %s WHERE %s = $1", identifier, table, identifier), feature)
        if err != nil {
            handleError(w, err.Error())
            return
        }

不建议这是最好的方法,但在我的情况下有效。

【讨论】:

    【解决方案2】:

    当您使用 http.Error 函数时,错误消息应该是一个字符串。对于简单的测试,我建议采取这一行

    http.Error(w, err.Error(), http.StatusInternalServerError)
    

    并将其更改为类似

    http.Error(w,"there was an error", http.StatusInternalServerError)
    

    并查看该响应是否通过。如果确实如此,您可能正在尝试在 http.Error() 中传递不是字符串的内容

    【讨论】:

    • 如果err 是一个错误接口,那么 err.Error() 必须是定义的字符串。它也不会编译。
    猜你喜欢
    • 2018-04-18
    • 1970-01-01
    • 2016-05-23
    • 2014-11-28
    • 2023-03-15
    • 2022-07-17
    • 1970-01-01
    • 1970-01-01
    • 2016-05-14
    相关资源
    最近更新 更多