首页 > 其他分享 >Go - Web Application 7

Go - Web Application 7

时间:2024-09-05 19:25:21浏览次数:5  
标签:Web http addr err Server Application Error Go logger

The http.Server struct

Although http.ListenAndServe() is very useful in short examples and tutorials, in real-world applications it’s more common to manually create and use a http.Server struct instead. Doing this opens up the opportunity to customize the behavior of your server.

So in preparation for that, let’s quickly update our main.go file to stop using the http.ListenAndServe() shortcut, and manually create and use a http.Server struct instead.

func main() {
    addr := flag.String("addr", ":4000", "HTTP network address")
    dbDriver := flag.String("dbdriver", "mysql", "Database driver name")
    dsn := flag.String("dsn",
        "zeb:zebpwd@tcp(localhost:3306)/snippetbox?parseTime=true",
        "MySQL data source name")
    flag.Parse()

    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))

    db, err := openDB(*dbDriver, *dsn)
    if err != nil {
        logger.Error(err.Error())
        os.Exit(1)
    }
    defer db.Close()

    templateCache, err := newTemplateCache()
    if err != nil {
        logger.Error(err.Error())
        os.Exit(1)
    }

    formDecoder := form.NewDecoder()

    sessionManager := scs.New()
    sessionManager.Store = mysqlstore.New(db)
    sessionManager.Lifetime = 12 * time.Hour

    app := &application{
        logger:         logger,
        snippet:        &models.SnippetModel{DB: db},
        templateCache:  templateCache,
        formDecoder:    formDecoder,
        sessionManager: sessionManager,
    }

    // Initialize a new http.Server struct. We set the Addr and Handler fields so that the server 
    // uses the same network address and routes as before.
    srv := &http.Server{
        Addr: *addr,
        Handler: app.routes(),
    }

    logger.Info("starting server", "addr", *addr)

    // Call the ListenAndServe() method on our new http.Server struct to start the server.
    err = srv.ListenAndServe()
    logger.Error(err.Error())
    os.Exit(1)
}

 

The server error log

It’s important to be aware that Go’s http.Server may write its own log entries relating to things like unrecovered panics, or problems accepting or writing to HTTP connections.

By default, it writes these entries using the standard logger — which means they will be written to the standard error stream (instead of standard out like our other log entries), and they won’t be in the same format as the rest of our nice structured log entries.

To demonstrate this, let’s add a deliberate error to our application and set a Content-Length header with an invalid value on our responses. Go ahead and update the render() helper like so:

func (app *application) render(w http.ResponseWriter, 
                               r *http.Request, 
                               status int, 
                               page string, 
                               data templateData) {
    ts, ok := app.templateCache[page]
    if !ok {
        err := fmt.Errorf("the template %s does not exist", page)
        app.serverError(w, r, err)
        return
    }

    buf := new(bytes.Buffer)

    err := ts.ExecuteTemplate(buf, "base", data)
    if err != nil {
        app.serverError(w, r, err)
        return
    }

    // Deliberate error: set a Content-Length header with an invalid (non-integer) value.
    w.Header().Set("Content-Length", "this isn't an integer!")

    w.WriteHeader(status)

    buf.WriteTo(w)
}

Then run the application, make a request to http://localhost:4000 , and check the application log. You should see that it looks similar to this:

zzh@ZZHPC:/zdata/Github/snippetbox$ go run ./cmd/web
time=2024-09-05T19:13:17.197+08:00 level=INFO msg="starting server" addr=:4000
time=2024-09-05T19:13:28.452+08:00 level=INFO msg="received request" ip=[::1]:57134 proto=HTTP/1.1 method=GET uri=/
2024/09/05 19:13:28 http: invalid Content-Length of "this isn't an integer!"

Unfortunately, it’s not possible to configure http.Server to use our new structured logger directly. Instead, we have to convert our structured logger handler into a *log.Logger which writes log entries at a specific fixed level, and then register that with the http.Server . We can do this conversion using the slog.NewLogLogger() function, like so:

func main() {
    addr := flag.String("addr", ":4000", "HTTP network address")
    dbDriver := flag.String("dbdriver", "mysql", "Database driver name")
    dsn := flag.String("dsn",
        "zeb:zebpwd@tcp(localhost:3306)/snippetbox?parseTime=true",
        "MySQL data source name")
    flag.Parse()

    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))

    db, err := openDB(*dbDriver, *dsn)
    if err != nil {
        logger.Error(err.Error())
        os.Exit(1)
    }
    defer db.Close()

    templateCache, err := newTemplateCache()
    if err != nil {
        logger.Error(err.Error())
        os.Exit(1)
    }

    formDecoder := form.NewDecoder()

    sessionManager := scs.New()
    sessionManager.Store = mysqlstore.New(db)
    sessionManager.Lifetime = 12 * time.Hour

    app := &application{
        logger:         logger,
        snippet:        &models.SnippetModel{DB: db},
        templateCache:  templateCache,
        formDecoder:    formDecoder,
        sessionManager: sessionManager,
    }

    srv := &http.Server{
        Addr:    *addr,
        Handler: app.routes(),
        // Create a *log.Logger from our structured logger handler, which writes log entries at
        // Error level, and assign it to the ErrorLog field. If you would prefer to log the
        // server errors at Warn level instead, you could pass slog.LevelWarn as the final
        // parameter.
        ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
    }

    logger.Info("starting server", "addr", *addr)

    err = srv.ListenAndServe()
    logger.Error(err.Error())
    os.Exit(1)
}

 

zzh@ZZHPC:/zdata/Github/snippetbox$ go run ./cmd/web
time=2024-09-05T19:24:08.317+08:00 level=INFO msg="starting server" addr=:4000
time=2024-09-05T19:24:16.686+08:00 level=INFO msg="received request" ip=[::1]:47308 proto=HTTP/1.1 method=GET uri=/
time=2024-09-05T19:24:16.689+08:00 level=ERROR msg="http: invalid Content-Length of \"this isn't an integer!\""

 

标签:Web,http,addr,err,Server,Application,Error,Go,logger
From: https://www.cnblogs.com/zhangzhihui/p/18399111

相关文章

  • 20240905_182821 python 快速体验正则表达式 获取web的url
    导入正则模块元字符\d,匹配一个数字.,匹配任意符号+,修饰左边的东西让它可以匹配一次或无穷次search方法结果=re.search(规则,目标字符串)如果匹配成功可以有结果如果匹配不成功结果就是Nonesearch的结果如果匹配成功了就会得到一个对象想要拿到匹配的值可以让这个结......
  • Web 服务器怎么测压? 可用什么软件?
    一、测试方法1.确定测试目标•明确要测试的Web服务器的关键性能指标,如响应时间、吞吐量、并发用户数等。•例如,若目标是确保在高并发情况下服务器仍能保持快速响应,就需要重点关注响应时间和并发用户数。2.设计测试场景•模拟不同的用户行为,如正常浏览、提交表单、......
  • golang实现ip地址扫描
    Golang实现IP地址扫描原创 GoOfficialBlog GoOfficialBlog  2024年09月05日18:13 中国香港 听全文你是否想过哪些设备连接到了家里的Wi-Fi网络?无论是出于安全目的还是单纯的好奇心,我们都可以去了解一下家庭网络中的设备情况。在本文中,我们将介绍如何使用......
  • AI Logo制作工具网站——LogoAI.ai
    AILogo制作工具,可通过输入文本生成Logo。可自定义颜色、字体、布局等,生成的Logo可以无水印下载。功能介绍:免费每日使用配额:每天可免费使用AI生成Logo。高级自定义选项:支持对Logo的颜色、字体、布局和图标进行自定义设计,以适应不同需求。无水印下载:生成的Logo无水印,可以直接......
  • 万字解析qinguoyi / TinyWebServer项目的源码
    前言项目地址项目详细介绍本文章适合刚学习完C++基础知识并尝试实现一个网络编程项目的同学,其中包含了该项目的代码逐行注释和解析以及许多刚学习网络编程中会遇到的疑问。项目简介:Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器.使用线......
  • WebGL_0020:threejs 加载glb模型,加载图片贴图,加载canvas贴图,创建精灵模型并贴图
    1,import*asTHREEfrom'three';importtype{MapViewer}from'@/utils/map3d/mapViewer';import{STATIC_URL}from'@/config';import{GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader';constgetSpri......
  • 基于django+vue羽毛球俱乐部管理系统设计与实现【开题报告+程序+论文】-计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着全民健身热潮的兴起,羽毛球作为一项低门槛、高趣味性的运动,深受广大运动爱好者的喜爱。羽毛球俱乐部的数量迅速增长,为满足会员的多元化......
  • 基于django+vue与spring的药品销售管理系统设计与实现【开题报告+程序+论文】计算机毕
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着医药行业的快速发展与市场竞争的日益激烈,药品销售管理成为医药企业提升运营效率、保障药品质量、优化客户服务的关键环节。传统的手工......
  • django 自定义中间件
    概述中间件是Django请求/响应处理的框架,用于全局改变Django的请求输入或响应输出。在请求阶段,在调用视图之前,Django按照定义settings.MIDDLEWARE的顺序应用中间件MIDDLEWARE,自顶向下。中间件的结构:classSimpleMiddleware:def__init__(self,get_response):......
  • 【转载】golang内存分配
     同时Go对于GC后回收的内存页,并不是马上归还给操作系统,而是会延迟归还,用于满足未来的内存需求.  在1.10以前go的堆地址空间是线性连续扩展的,比如在1.10(linuxamd64)中,最大可扩展到512GB.因为go在gc的时候会根据拿到的指针地址来判断是否位于......