当前位置: 首页 > news >正文

南京做网站外包公司怎么做网站推广

南京做网站外包,公司怎么做网站推广,淘宝客怎么自己做网站及APP,提高网站建设水平通过go语言原生http中响应错误的实现方法,逐步了解和使用微服务框架 kratos 的错误处理方式,以及探究其实现原理。 一、go原生http响应错误信息的处理方法 处理方法: ①定义返回错误信息的结构体 ErrorResponse // 定义http返回错误信息的…

 通过go语言原生http中响应错误的实现方法,逐步了解和使用微服务框架 kratos 的错误处理方式,以及探究其实现原理。

一、go原生http响应错误信息的处理方法

  • 处理方法:

①定义返回错误信息的结构体 ErrorResponse

// 定义http返回错误信息的结构体
type ErrorResponse struct {Code    int    `json:"code"`Message string `json:"message"`
}

②根据业务逻辑,为结构体赋值相应的错误信息

//这里为了简化函数,不进行业务逻辑判断,而直接返回错误信息
er := &ErrorResponse{Code:    403,Message: "用户名不能为空",
}

③将错误信息序列化,并写入到 http.ResponseWriter 中

// 设置响应头为JSON类型
w.Header().Set("Content-Type", "application/json")// 设置响应状态码为400
w.WriteHeader(http.StatusBadRequest)// 将ErrorResponse转换为JSON并写入响应体
//json.NewEncoder(w).Encode(he)//将错误信息结构体序列化,并返回
res, _ := json.Marshal(er)
w.Write(res)

  • 代码示例:
package mainimport ("encoding/json""net/http"
)// 定义http返回错误信息的结构体
type ErrorResponse struct {Code    int    `json:"code"`Message string `json:"message"`
}func Login(w http.ResponseWriter, r *http.Request) {//这里为了简化函数,不进行业务逻辑判断,而直接返回错误信息er := &ErrorResponse{Code:    403,Message: "用户名不能为空",}// 设置响应头为JSON类型w.Header().Set("Content-Type", "application/json")// 设置响应状态码为400w.WriteHeader(http.StatusBadRequest)// 将ErrorResponse转换为JSON并写入响应体//json.NewEncoder(w).Encode(he)//将错误信息结构体序列化,并返回res, _ := json.Marshal(er)w.Write(res)
}func main() {//创建一个 HTTP 请求路由器mux := http.NewServeMux()mux.Handle("/login", http.HandlerFunc(Login))http.ListenAndServe(":8081", mux)
}
  • 效果演示:

二、微服务框架kratos响应错误的方式

Kratos官网有关错误处理的介绍:错误处理 | Kratos

Kratos 有关错误处理的 examples 代码见:examples/errors 、examples/http/errors

1、kratos默认的错误信息格式
  • kratos响应错误信息的默认JSON格式为:
{// 错误码,跟 http-status 一致,并且在 grpc 中可以转换成 grpc-status"code": 500,// 错误原因,定义为业务判定错误码"reason": "USER_NOT_FOUND",// 错误信息,为用户可读的信息,可作为用户提示内容"message": "invalid argument error",// 错误元信息,为错误添加附加可扩展信息"metadata": {"foo": "bar"}
}
  • 使用方法:

①导入 kratos 的 errors 包

import "github.com/go-kratos/kratos/v2/errors"

②在业务逻辑中需要响应错误时,用 New 方法生成错误信息(或通过 proto 生成的代码响应错误)

注意:这里的 New 方法是 Kratos 框架中的 errros.New,而不是 go 原生的 errors.New

func NewLoginRequest(username, password string) (*LoginRequest, error) {// 校验参数if username == "" {//通过 New 方法创建一个错误信息err := errors.New(500, "USER_NAME_EMPTY", "用户名不能为空")// 传递metadataerr = err.WithMetadata(map[string]string{ "remark": "请求参数中的 phone 字段为空",})return nil, err}if password == "" {// 通过 proto 生成的代码响应错误,并且包名应替换为自己生成代码后的 package name      return nil, api.ErrorPasswordIsEmpty("密码不能为空")}return &LoginRequest{username: username,password: password,}, nil
}
  • 返回结果:

2、自定义错误信息格式

如果不想使用 kratos 默认的错误响应格式,可以自定义错误信息处理格式,方法如下:

①自定义错误信息结构体

type HTTPError struct {Code     int    `json:"code"`Message  string `json:"message"`MoreInfo string `json:"moreInfo"`
}

②实现 FromError、errorEncoder 等方法

func (e *HTTPError) Error() string {return fmt.Sprintf("HTTPError code: %d message: %s", e.Code, e.Message)
}// FromError try to convert an error to *HTTPError.
func FromError(err error) *HTTPError {if err == nil {return nil}if se := new(HTTPError); errors.As(err, &se) {return se}return &HTTPError{Code: 500}
}func errorEncoder(w stdhttp.ResponseWriter, r *stdhttp.Request, err error) {se := FromError(err)codec, _ := http.CodecForRequest(r, "Accept")body, err := codec.Marshal(se)if err != nil {w.WriteHeader(500)return}w.Header().Set("Content-Type", "application/"+codec.Name())w.WriteHeader(se.Code)_, _ = w.Write(body)
}

③创建 http.Server 时,使用函数 http.ErrorEncoder() 将上述 errorEncoder 添加到 ServerOption 中

httpSrv := http.NewServer(http.Address(":8000"),http.ErrorEncoder(errorEncoder),
)

④业务逻辑中需要响应错误的地方返回自定义消息对象

return &HTTPError{Code: 400, Message: "用户名不存在", MoreInfo: "请求参数中 userName = 张三"}
  • 完整代码示例为:
package mainimport ("errors""fmt""log"stdhttp "net/http""github.com/go-kratos/kratos/v2""github.com/go-kratos/kratos/v2/transport/http"
)// HTTPError is an HTTP error.
type HTTPError struct {Code     int    `json:"code"`Message  string `json:"message"`MoreInfo string `json:"moreInfo"`
}func (e *HTTPError) Error() string {return fmt.Sprintf("HTTPError code: %d message: %s", e.Code, e.Message)
}// FromError try to convert an error to *HTTPError.
func FromError(err error) *HTTPError {if err == nil {return nil}if se := new(HTTPError); errors.As(err, &se) {return se}return &HTTPError{Code: 500}
}func errorEncoder(w stdhttp.ResponseWriter, r *stdhttp.Request, err error) {se := FromError(err)codec, _ := http.CodecForRequest(r, "Accept")body, err := codec.Marshal(se)if err != nil {w.WriteHeader(500)return}w.Header().Set("Content-Type", "application/"+codec.Name())w.WriteHeader(se.Code)_, _ = w.Write(body)
}func main() {httpSrv := http.NewServer(http.Address(":8082"),http.ErrorEncoder(errorEncoder),)router := httpSrv.Route("/")router.GET("login", func(ctx http.Context) error {return &HTTPError{Code: 400, Message: "用户名不存在", MoreInfo: "请求参数中 userName = 张三"}})app := kratos.New(kratos.Name("mux"),kratos.Server(httpSrv,),)if err := app.Run(); err != nil {log.Fatal(err)}
}
  • 返回结果:

3、kratos返回错误信息JSON的源码探究

至此,了解了 go 原生 http 和微服务框架 kratos 响应错误信息的处理方式,对比可发现:

①在原生http响应处理中,我们先将错误消息结构体序列化 res, _ := json.Marshal(er),然后通过 http.ResponseWriter.Write(res) 写入错误信息JSON并返回

②在 kratos 中,我们在业务处理函数中仅仅通过 return errors.New() 返回了一个 error,并没有将其序列化,但整个http请求却返回了一个有关错误信息的 json 字符串

是什么原因呢?原来是 kratos 框架内部完成了将错误信息结构体序列化并写入http.ResponseWriter的过程。

具体实现方式如下:

  • http server 结构体 Server 中含有一个字段 ene EncodeErrorFunc,专门用来进行错误处理
//http/server.go
// Server is an HTTP server wrapper.
type Server struct {*http.Serverlis         net.ListenertlsConf     *tls.Configendpoint    *url.URLerr         errornetwork     stringaddress     stringtimeout     time.Durationfilters     []FilterFuncmiddleware  matcher.MatcherdecVars     DecodeRequestFuncdecQuery    DecodeRequestFuncdecBody     DecodeRequestFuncenc         EncodeResponseFuncene         EncodeErrorFunc           // 用于错误处理strictSlash boolrouter      *mux.Router
}//http/codec.go
// EncodeErrorFunc is encode error func.
type EncodeErrorFunc func(http.ResponseWriter, *http.Request, error)
  • 使用 NewServer() 创建时 http Server 时,ene 属性会默认为 DefaultErrorEncoder,该函数会将序列化错误信息,并写入到 http.ResponseWriter 中
//http/server.go
// NewServer creates an HTTP server by options.
func NewServer(opts ...ServerOption) *Server {srv := &Server{network:     "tcp",address:     ":0",timeout:     1 * time.Second,middleware:  matcher.New(),decVars:     DefaultRequestVars,decQuery:    DefaultRequestQuery,decBody:     DefaultRequestDecoder,enc:         DefaultResponseEncoder,ene:         DefaultErrorEncoder,     //默认的错误处理函数strictSlash: true,router:      mux.NewRouter(),}for _, o := range opts {o(srv)}srv.router.StrictSlash(srv.strictSlash)srv.router.NotFoundHandler = http.DefaultServeMuxsrv.router.MethodNotAllowedHandler = http.DefaultServeMuxsrv.router.Use(srv.filter())srv.Server = &http.Server{Handler:   FilterChain(srv.filters...)(srv.router),TLSConfig: srv.tlsConf,}return srv
}//http/codec.go
// DefaultErrorEncoder encodes the error to the HTTP response.
func DefaultErrorEncoder(w http.ResponseWriter, r *http.Request, err error) {se := errors.FromError(err)codec, _ := CodecForRequest(r, "Accept")body, err := codec.Marshal(se)    //序列化错误信息结构体if err != nil {w.WriteHeader(http.StatusInternalServerError)return}w.Header().Set("Content-Type", httputil.ContentType(codec.Name()))w.WriteHeader(int(se.Code))_, _ = w.Write(body)            //将序列化的结果写入到响应中
}
  • 路由处理函数 router.GET() 等会调用 Router.Handle, 其中会判断 HandlerFunc 是否有返回错误,如果有,则会调用 server.ene 函数,从而完成错误信息序列化并返回
//main.go
func main() {httpSrv := http.NewServer(http.Address(":8082"),)router := httpSrv.Route("/")router.GET("login", func(ctx http.Context) error {return errors.New(500, "USER_NOT_FOUND", "用户名不存在")})
}//http/router.go
// GET registers a new GET route for a path with matching handler in the router.
func (r *Router) GET(path string, h HandlerFunc, m ...FilterFunc) {r.Handle(http.MethodGet, path, h, m...)
}//http/router.go
// Handle registers a new route with a matcher for the URL path and method.
func (r *Router) Handle(method, relativePath string, h HandlerFunc, filters ...FilterFunc) {next := http.Handler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {ctx := r.pool.Get().(Context)ctx.Reset(res, req)//重点:这里判断路由处理函数是否返回了 error,如果是,则调用 server.ene 函数,序列化错误信息并返回if err := h(ctx); err != nil {r.srv.ene(res, req, err)}ctx.Reset(nil, nil)r.pool.Put(ctx)}))next = FilterChain(filters...)(next)next = FilterChain(r.filters...)(next)r.srv.router.Handle(path.Join(r.prefix, relativePath), next).Methods(method)
}
  • 自定义错误消息结构体后,创建 http server 时,通过 http.ErrorEncoder(errorEncoder) 将自定义的错误处理函数赋值给 server.ene,替换了默认的 DefaultErrorEncoder
// main.go
//自定义的错误处理函数
func errorEncoder(w stdhttp.ResponseWriter, r *stdhttp.Request, err error) {se := FromError(err)codec, _ := http.CodecForRequest(r, "Accept")body, err := codec.Marshal(se)if err != nil {w.WriteHeader(500)return}w.Header().Set("Content-Type", "application/"+codec.Name())w.WriteHeader(se.Code)_, _ = w.Write(body)
}// main.go
func main() {httpSrv := http.NewServer(http.Address(":8082"),http.ErrorEncoder(errorEncoder),  // 将自定义的错误处理函数赋值给 sever)
}// http/server.go
// ErrorEncoder with error encoder.
func ErrorEncoder(en EncodeErrorFunc) ServerOption {return func(o *Server) {o.ene = en}
}

http://www.hrbkazy.com/news/30388.html

相关文章:

  • 钓鱼网站的危害线下推广方式
  • 网站开发工作内容上海谷歌seo推广公司
  • 龙华网站建设谷歌seo排名优化
  • 河南锦路路桥建设有限公司网站网站检测中心
  • 奎屯市网站销售的三个核心点
  • jfinal网站开发模板一个产品的营销方案
  • 免费制作图片的软件有哪些白杨seo教程
  • 贵阳网站建设哪家好方舟优秀营销软文范例800字
  • 能建设传奇私服网站的空间推广平台app
  • 做网站一般费用多少在线crm网站建站
  • 武汉制作网站公司页面seo是什么意思
  • 网站建设联系方式网络推广公司深圳
  • 专业做网站的企业首页排名优化公司
  • 寻找做项目的网站百度云网页版入口
  • 网站平台建设需要注意的是百度推广怎么使用教程
  • 做国外有那些网站比较好的app运营推广策划方案
  • 锦州市做网站韶关新闻最新今日头条
  • 专业的培训行业网站开发百度热搜榜第一
  • 如何直到网站是用什么模板做的广告推广图片
  • 同德县网站建设公司seo优化工具
  • 网站建设个人工作室引擎优化seo怎么做
  • 响应式相册网站模板网站流量排名查询工具
  • 企业网站模板建站流程我在百度下的订单如何查询
  • 临沂网站制作公司搜索引擎优化的核心及内容
  • 重庆网站设计总部网上教育培训机构
  • 怎么设置iis默认网站网店代运营可靠吗
  • 做网站需要学多久怎么免费注册域名
  • 网站关键词百度搜不到360免费做网站
  • php 小企业网站 cmsaso优化排名推广
  • 网站qq登录 开发网站关键词优化多少钱