golang处理HTTP问题详情(Problem Details)的插件库go-problemdetails的使用

Golang处理HTTP问题详情(Problem Details)的插件库go-problemdetails的使用

简介

go-problemdetails是一个实现了RFC 7807标准(Problem Details for HTTP APIs)的Golang包。它可以帮助开发者以标准化的方式返回HTTP API错误信息。

安装

go get github.com/mvmaasakkers/go-problemdetails

基本用法

ProblemDetails结构体实现了error接口,可以作为错误使用。ProblemType接口可以用来创建预定义的ProblemDetails扩展,同样实现了error接口。

简单创建

根据HTTP状态码创建ProblemDetails:

problemDetails := problemdetails.NewHTTP(http.StatusNotFound)

这将生成一个JSON格式的响应:

{
  "type": "about:blank",
  "title": "Not Found",
  "status": 404
}

或XML格式:

<problem xmlns="urn:ietf:rfc:7807">
    <type>about:blank</type>
    <title>Not Found</title>
    <status>404</status>
</problem>

详细创建

使用更详细的构造函数:

problemDetails := problemdetails.New(
    http.StatusNotFound, 
    "https://example.net/problem/object_not_found", 
    "Object not found", 
    "Object with id 1234 was not found, another id should be given.", 
    "https://api.example.net/objects/1234"
)

这将生成:

{
  "type": "https://example.net/problem/object_not_found",
  "title": "Object not found",
  "status": 404,
  "detail": "Object with id 1234 was not found, another id should be given.",
  "instance": "https://api.example.net/objects/1234"
}

或XML格式:

<problem xmlns="urn:ietf:rfc:7807">
    <type>https://example.net/problem/object_not_found</type>
    <title>Object not found</title>
    <status>404</status>
    <detail>Object with id 1234 was not found, another id should be given.</detail>
    <instance>https://api.example.net/objects/1234</instance>
</problem>

HTTP辅助函数

为方便使用,提供了两个输出处理器:

  • ProblemDetails.ServeJSON 用于JSON格式
  • ProblemDetails.ServeXML 用于XML格式

示例:

problemdetails.NewHTTP(http.StatusNotFound).ServeJSON(w, r)

完整示例

下面是一个完整的HTTP服务器示例:

package main

import (
	"net/http"

	"github.com/mvmaasakkers/go-problemdetails"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// 返回404错误
		problemdetails.NewHTTP(http.StatusNotFound).ServeJSON(w, r)
	})

	http.HandleFunc("/object", func(w http.ResponseWriter, r *http.Request) {
		// 返回自定义错误
		pd := problemdetails.New(
			http.StatusNotFound,
			"https://example.net/problem/object_not_found",
			"Object not found",
			"Object with id 1234 was not found, another id should be given.",
			"https://api.example.net/objects/1234",
		)
		pd.ServeJSON(w, r)
	})

	http.ListenAndServe(":8080", nil)
}

这个示例展示了如何使用go-problemdetails库来返回标准化的HTTP错误响应。


更多关于golang处理HTTP问题详情(Problem Details)的插件库go-problemdetails的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang处理HTTP问题详情(Problem Details)的插件库go-problemdetails的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用go-problemdetails处理HTTP问题详情

go-problemdetails是一个用于处理HTTP问题详情(RFC 7807)的Golang库,它提供了一种标准化的方式来表示HTTP API中的错误信息。下面我将详细介绍如何使用这个库。

安装

首先安装go-problemdetails库:

go get github.com/StevenACoffman/go-problemdetails

基本用法

1. 创建问题详情响应

package main

import (
	"net/http"

	"github.com/StevenACoffman/go-problemdetails"
)

func main() {
	http.HandleFunc("/example", func(w http.ResponseWriter, r *http.Request) {
		// 创建一个问题详情响应
		detail := problemdetails.NewProblem(
			"https://example.com/probs/out-of-credit",
			"You do not have enough credit.",
			"Your current balance is 30, but that costs 50.",
			http.StatusForbidden,
		)
		
		// 可选:添加自定义字段
		detail.With("balance", 30).
			With("accounts", []string{"/account/12345", "/account/67890"})
		
		// 发送响应
		problemdetails.ServeProblem(w, r, detail)
	})

	http.ListenAndServe(":8080", nil)
}

2. 使用预定义的问题类型

func handler(w http.ResponseWriter, r *http.Request) {
    // 使用预定义的问题类型
    detail := problemdetails.NewStatusProblem(http.StatusNotFound)
    problemdetails.ServeProblem(w, r, detail)
}

3. 自定义中间件处理错误

func ProblemDetailsMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        defer func() {
            if err := recover(); err != nil {
                var detail *problemdetails.Problem
                
                switch e := err.(type) {
                case *problemdetails.Problem:
                    detail = e
                case error:
                    detail = problemdetails.NewStatusProblem(http.StatusInternalServerError).
                        With("error", e.Error())
                default:
                    detail = problemdetails.NewStatusProblem(http.StatusInternalServerError)
                }
                
                problemdetails.ServeProblem(w, r, detail)
            }
        }()
        
        next.ServeHTTP(w, r)
    })
}

高级用法

1. 自定义问题类型

// 定义自定义问题类型
var InsufficientCreditProblem = problemdetails.NewProblemType(
    "https://example.com/probs/insufficient-credit",
    "Insufficient Credit",
)

func creditHandler(w http.ResponseWriter, r *http.Request) {
    detail := problemdetails.NewProblemFromType(
        InsufficientCreditProblem,
        "Your credit balance is too low",
        "Current balance: 30, required: 50",
        http.StatusForbidden,
    ).With("balance", 30).With("required", 50)
    
    problemdetails.ServeProblem(w, r, detail)
}

2. 与标准库错误集成

func someOperation() error {
    return problemdetails.NewStatusProblem(http.StatusBadRequest).
        With("details", "Invalid input parameter").
        With("field", "username")
}

func handler(w http.ResponseWriter, r *http.Request) {
    if err := someOperation(); err != nil {
        if pd, ok := err.(*problemdetails.Problem); ok {
            problemdetails.ServeProblem(w, r, pd)
            return
        }
        // 处理其他类型的错误
    }
    // 正常处理
}

3. 从错误中提取问题详情

func extractProblemDetails(err error) *problemdetails.Problem {
    if pd, ok := err.(*problemdetails.Problem); ok {
        return pd
    }
    return problemdetails.NewStatusProblem(http.StatusInternalServerError).
        With("error", err.Error())
}

响应示例

使用上述代码生成的响应如下:

{
  "type": "https://example.com/probs/out-of-credit",
  "title": "You do not have enough credit.",
  "detail": "Your current balance is 30, but that costs 50.",
  "status": 403,
  "balance": 30,
  "accounts": [
    "/account/12345",
    "/account/67890"
  ]
}

最佳实践

  1. 使用标准问题类型:尽可能使用预定义的标准问题类型
  2. 包含足够信息:提供足够的信息帮助客户端理解问题
  3. 保持一致性:在整个API中保持一致的错误格式
  4. 适当的状态码:使用正确的HTTP状态码
  5. 文档化:在API文档中记录可能返回的问题类型

go-problemdetails库提供了一种符合RFC 7807标准的方式来处理HTTP API中的错误,使客户端能够以一致的方式理解和处理错误情况。

回到顶部