美文网首页go
【Go Web开发】HTTP服务器基础

【Go Web开发】HTTP服务器基础

作者: Go语言由浅入深 | 来源:发表于2022-01-12 22:50 被阅读0次

    简单的HTTP服务器

    现在项目的框架结构已经就绪,让我们将注意力集中在启动和运行HTTP服务器上。

    首先,我们将服务器配置为只有一个路由:/v1/healthcheck。这条路由将返回有关API服务的一些基本信息,包括其当前版本号和操作环境(开发、测试、生产等)。

    URL模式 Handler 操作
    /v1/healthcheck healthcheckHandler 显示应用信息

    如果你跟着本文操作,下面打开cmd/api/main.go文件用以下代码替换’hello world‘应用:

    File:main.go

    package main
    
    import (
        "flag"
        "fmt"
        "log"
        "net/http"
        "os"
        "time"
    )
    
    // 声明一个包含应用程序版本号的字符串. 在本书的后面,我们将在构建时自动生成它
    //但是现在我们只将版本号存储为一个硬编码的全局常量.
    const version = "1.0.0"
    
    // 定义一个配置结构体来保存应用程序的所有配置设置.
    //目前,唯一的配置是服务器监听的端口和应用程序的环境名称 (开发, 预发, 生成等等)
    //将从命令行参数中读取这些配制信息
    type config struct {
        port int
        env  string
    }
    
    // 定义一个application结构体来保存HTTP处理程序的依赖项
    //目前,这只包含配置实例的一个副本和日志对象,但随着项目深入会增加更多内容
    type application struct {
        config config
        logger *log.Logger
    }
    
    func main() {
        // 声明一个配置结构体实例
        var cfg config
    
        // 从命令行参数中将port和env读取到配制结构体实例当中。
        //默认端口使用4000以及环境信息使用开发环境development
        flag.IntVar(&cfg.port, "port", 4000, "API server port")
        flag.StringVar(&cfg.env, "env", "development", "Environment (development|staging|production)")
        flag.Parse()
    
        // 初始化日志对象,将消息写入到标准输出。 以当前日期和时间为前缀
        logger := log.New(os.Stdout, "", log.Ldate|log.Ltime)
    
        // 声明应用程序结构的实例, 包含配制对象实例和日志对象。
        app := &application{
            config: cfg,
            logger: logger}
    
        // 申明一个新的servemux并添加/v1/healthcheck路由,将请求路由到即将实现的handler处理程序中去
        mux := http.NewServeMux()
        mux.HandleFunc("/v1/healthcheck", app.healthcheckHandler)
    
        // 使用一些合理的超时设置声明HTTP服务器
        //使用配制对象中的端口好以及创建的servemux作为handler
        srv := &http.Server{
            Addr:         fmt.Sprintf(":%d", cfg.port),
            Handler:      mux,
            IdleTimeout:  time.Minute,
            ReadTimeout:  10 * time.Second,
            WriteTimeout: 30 * time.Second,
        }
    
        // 启动HTTP服务
        logger.Printf("starting %s server on %s", cfg.env, srv.Addr)
        err := srv.ListenAndServe()
        logger.Fatal(err)
    }
    
    

    创建healthcheck处理程序

    接下来我们需要创建用于响应HTTP请求的healthcheckHandler方法。现在,我们将保持这个处理程序中的逻辑非常简单,只让它返回一个包含三段信息的纯文本响应:

    • 一个固定的“status: available”字符串
    • API版本从硬编码version常量获取
    • 操作环境名从命令行参数读取存在env中

    继续创建cmd/api/healthcheck.go文件:

    $ touch cmd/api/healthcheck.go
    

    添加如下代码到文件中:

    File:cmd/api/healthcheck.go

    package main
    
    import (
        "fmt"
        "net/http"
    )
    
    //申明一个handler返回应用程序状态,操作环境和版本
    func (app *application) healthcheck(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "status: available")
        fmt.Fprintf(w, "environment %s\n", app.config.env)
        fmt.Fprintf(w, "version: %s\n", version)
    }
    
    

    这里需要指出的重要一点是,healthcheckHandler是作为application结构体上的一个方法实现的.

    这是一种有效且惯用的方法,使我们的处理程序可以使用依赖项,而不需要借助全局变量或闭包——当我们在main()中初始化healthcheckHandler时,任何依赖项都可以简单地作为一个字段包含在应用程序结构中。

    我们可以看到上面的代码中已经使用了这个模式,其中通过调用app.config.env从应用程序结构中检索操作环境名称。

    演示

    代码我们来试试接口,请确保你的所有更改都已保存,然后再次使用go run命令来执行cmd/api包中的代码。您应该会看到一条日志消息,确认HTTP服务器正在运行,类似如下:

     $ go run ./cmd/api
    2021/11/15 19:42:50 starting development server on :4000
    

    当服务器运行时,继续尝试在浏览器中访问localhost:4000/v1/healthcheck。你应该从healthcheckHandler得到如下响应:



    或者,您可以使用curl工具从您的终端发出请求:

    $ curl -i localhost:4000/v1/healthcheck
    HTTP/1.1 200 OK
    Date: Mon, 05 Apr 2021 17:46:14 GMT Content-Length: 58
    Content-Type: text/plain; charset=utf-8
    status: available environment: development version: 1.0.0
    

    注意:上面命令中的-i标志表示curl显示HTTP响应头和响应体。

    如果你想验证在命令行参数是否正常工作,通过指定port和env值然后在启动服务器。你应该可以看到日志信息,如下:

     $ go run ./cmd/api -port=3030 -env=production
    2021/04/05 19:48:34 starting production server on :3030
    

    附加说明

    API版本

    支持真实业务和用户的api经常需要随着时间的推移而更改其功能和API——有时是以一种向后不兼容的方式。因此,为了避免客户端出现问题和困惑,最好实现某种形式的API版本控制。

    通常有两种方法来实现:

    1、通过给所有url加上API版本的前缀,比如/v1/healthcheck或/v2/healthcheck。

    2、通过在请求和响应中使用自定义的Accept和Content-Type头来传递API版本,比如Accept: application/vnd.greenlight-v1。

    从HTTP语义的角度来看,使用请求头来传递API版本是一种“更纯粹”的方法。但从用户体验的角度来看,使用URL前缀可能更好。开发者一眼就能看出API的版本,也意味着可以使用常规的浏览器来访问API(如果放在请求头就更不方便)。

    在整个应用中,我们将通过在所有URL路径前加上/v1/来对API进行版本化,就像我们在本章中对/v1/healthcheck接口所做的那样。

    相关文章

      网友评论

        本文标题:【Go Web开发】HTTP服务器基础

        本文链接:https://www.haomeiwen.com/subject/ufygcrtx.html