Golang: 创建Web服务
使用 Go 语言,我们可以轻松创建出 Web 服务,这一点比 Node.js 还要简单,今天就来总结一下 Go 语言中 Web 服务的创建方式。
首先,我们需要引入 net/http 这个包来处理 HTTP 请求,然后在指定的端口开启服务,下面来写一个最简单的 Web 服务程序:
// server.go
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", handler)
log.Println("go server listening at port 3000...")
err := http.ListenAndServe(":3000", nil)
if err != nil {
log.Fatal("err: ", err)
}
}
func handler(res http.ResponseWriter, req *http.Request) {
log.Println(req.URL.Path)
fmt.Fprintf(res, "URL.Path = %q\n", req.URL.Path)
}
上面代码中,我们会处理所有 3000 端口的请求,然后在页面显示请求的路径。另外,我们在代码中引入了 log 包,使用 log.Println(s) 方法打印信息,运行代码后,在浏览器请求 localhost:3000 及 localhost:3000/test,控制台打印信息如下:
$ go run server.go
2018/08/30 13:26:58 go server listening at port 3000...
2018/08/30 13:27:01 /
2018/08/30 13:27:07 /test
接下来,我们希望这个服务能够解析出浏览器的请求信息,返回并显示到页面,下面是经过改进后的代码:
// server.go
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", handler)
log.Println("go server listening at port 3000...")
err := http.ListenAndServe(":3000", nil)
if err != nil {
log.Fatal("err: ", err)
}
}
func handler(res http.ResponseWriter, req *http.Request) {
// 请求方法 请求地址 协议类型
fmt.Fprintf(res, "%s %s %s\n", req.Method, req.URL, req.Proto)
// 请求头信息
for k, v := range req.Header {
fmt.Fprintf(res, "Header[%q] = %q\n", k, v)
}
// 请求的服务器URL & 请求的远程地址
fmt.Fprintf(res, "Host = %q\n", req.Host)
fmt.Fprintf(res, "RemoteAddr = %q\n", req.RemoteAddr)
if err := req.ParseForm(); err != nil {
log.Print(err)
}
// 表单信息
for k, v := range req.Form {
fmt.Fprintf(res, "Form[%q] = %q\n", k, v)
}
}
在 handler 函数中,我们从 http.Request 中取出相应的 HTTP 请求信息,然后返回给浏览器,大家可以亲自运行以上代码,来观察实际效果。
接下来,我们希望做个小功能 - 统计用户的访问次数,这是一项很古老的技术了,在上个世纪的论坛网站中曾广泛应用。😃
我们改进后的代码如下:
// server.go
package main
import (
"fmt"
"log"
"sync"
"net/http"
)
var mutex sync.Mutex
var count int
func main() {
http.HandleFunc("/", handler)
// 添加/count路由及处理函数
http.HandleFunc("/count", counter)
log.Println("go server listening at port 3000...")
err := http.ListenAndServe(":3000", nil)
if err != nil {
log.Fatal("err: ", err)
}
}
// 每次访问时 count递增
func handler(res http.ResponseWriter, req *http.Request) {
mutex.Lock()
count++
mutex.Unlock()
fmt.Fprintf(res, "URL.Path = %q\n", req.URL.Path)
}
// 显示当前访问次数
func counter(res http.ResponseWriter, req *http.Request) {
mutex.Lock()
fmt.Fprintf(res, "Visit Count: %d\n", count)
mutex.Unlock()
}
这次我们引入了 sync 包,来应对并发访问带来的数据更新问题。sync.Mutex 类提供了 Lock() 和 Unlock() 方法,分别对更新操作进行加锁和解锁,保证 count 的递增操作不会受到并发访问的影响。
运行上面的代码,然后在浏览器中访问除 /count 之外的路径,都可以累积访问次数,最后,在访问 /count 路径时,会返回当前服务被访问的次数。
欢迎转载,转载请注明出处。