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
包里实现里我们想要的接口限流功能,内部是通过每次接口访问计数实现的,设计巧妙,代码不多可以进去看下具体实现。
未完待续...