Go语言实践Golang语言社区golang

golang创建http service的不同姿势

2021-03-06  本文已影响0人  生活简单些

  Golang创建Web Server其实很简单,并不需要象Java一样依赖配置web.xml、不需要写servlet、不需要Tomcat、更不需要Spring这类五花八门的第三方框架,Golang创建Web Server只需要Golang SDK自己足以,甚至beego、gin等这类所谓等封装式的框架也是多余的。

1. 最简单方式之一

package main

import (
    "fmt"
    "log"
    "net/http"
)

// Web api handle func, read request from `r` and write into `w`
func greet(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
}

func main() {
    // `Mux` is called `Route`, every web api should be registered on it
    route := http.DefaultServeMux

    // Register api is so easy
    route.HandleFunc("/", greet)

    // Launch http server and will print log when error occured
    log.Fatal(http.ListenAndServe(":8080", route))
}

2. 最简单的方式之二

package main

import (
    "fmt"
    "net/http"
)

func greet(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
}

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

Note: 你会发现route没了,不用路由了么?其实这是另一种懒写方式,用http.HandleFunc()方式注册接口是默认注册在http.DefaultServeMux上的,然后http.ListenAndServe(":8080", nil) 这里的nil为nil,其实默认内部也会使用http.DefaultServeMux的作为路由。

3. 允许参数配置的WebServer

package main

import (
    "fmt"
    "log"
    "net"
    "net/http"
)

func greet(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
}

func main() {
    router := http.DefaultServeMux
    router.HandleFunc("/", greet)

    // above cases, the `service` instance is created inside and is not visiable to us
    // here we expose `service`, so we can setup extra params on it
    server := http.Server{
        Handler: router,
    }
    server.SetKeepAlivesEnabled(false)
    server.ReadTimeout = 10000
    // server.xxx = xxx // many other settings

    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
        log.Fatal(err)
    }

    log.Fatal(server.Serve(listener))
}

Note: 因为Golang创建的Web Server默认是keep alive的,这将导致导致server和client每次建立的connection不会自动close,当http请求次数多了会占用很多内存,如果你的项目是只支持短连接的,那么 server.SetKeepAlivesEnabled(false)将做到每次连接即用即断。
同时另外一个好处是可以随时通过调用Shutdown(ctx)将server关闭。

4. 如何加载证书、密钥并启动Https Web Service

package main

import (
    "crypto/tls"
    "fmt"
    "log"
    "net"
    "net/http"
)

const (
    certFile = "./public.perm"
    keyFile  = "./private.key"
)

func greet(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
}

func main() {
    router := http.DefaultServeMux
    router.HandleFunc("/", greet)

    // create server
    server := http.Server{
        Handler: router,
    }
    server.SetKeepAlivesEnabled(false)

    // create listener
    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
        log.Fatal(err)
    }

    // validate certification
    if _, err := tls.LoadX509KeyPair(certFile, keyFile); err != nil {
        log.Fatal(err)
    }

    // start https server
    log.Fatal(server.ServeTLS(listener, certFile, keyFile))
}

Note: https的实现是用过调用server.ServeTLS(net.Listener, certFile, keyFile)实现的,需要额外传入certFile和keyFile,建议在启动server之前先检查证书的正确性,通过certificate, err := tls.LoadX509KeyPair(certFile, keyFile)可以验证正确是否,还能获得证书的额外信息。

5. Http接口如何限流

import (
    "..."

    // used by limited listener
    "golang.org/x/net/netutil"
)

const (
    certFile = "./public.perm"
    keyFile  = "./private.key"

    connLimits = 10000
)

// create listener
listener, err := net.Listen("tcp", ":8080")
if err != nil {
    log.Fatal(err)
}

// create limited listener with exist listener
listener = netutil.LimitListener(listener, connLimits)

// validate certification
if _, err := tls.LoadX509KeyPair(certFile, keyFile); err != nil {
    log.Fatal(err)
}

// start https server
log.Fatal(server.ServeTLS(listener, certFile, keyFile))

Note:golang.org/x/net/netutil 包里实现里我们想要的接口限流功能,内部是通过每次接口访问计数实现的,设计巧妙,代码不多可以进去看下具体实现。

未完待续...

上一篇 下一篇

猜你喜欢

热点阅读