开发Web服务程序
任务目标
- 熟悉 go 服务器工作原理
- 基于现有 web 库,编写一个简单 web 应用类似 cloudgo。
- 使用 curl 工具访问 web 程序
- 对 web 执行压力测试
熟悉 go 服务器工作原理
采用普通的C/S架构,使用IP:端口号
地址进行网络间信息交互。
服务端采用中间件(negroni
)创建服务器模块,将具体的业务处理Handler
和路由mux
都视作中间件,建立根据url
解析路由进行业务处理的服务端逻辑。
Negroni的结构:
type Negroni struct {
middleware middleware
handlers []Handler
}
依赖方法库negroni
和gorilla/mux
工作的流程如下:
在SaaS(软件即服务)规范下,服务端只提供数据,客户端负责对数据的渲染和呈现。
所以本次实验只完成服务端部分,客户端使用curl
工具代替,用于获取目标数据,检测服务端逻辑正确性。
编写一个简单 web 应用
negroni和mux结合,实现服务端的各种方式。
server := service.NewServer()
// Classic 返回带有默认中间件的Negroni实例指针:
n := negroni.Classic()
// New 创建 negroni 实例并返回其指针
return New(NewRecovery(),
NewLogger(),
NewStatic(http.Dir("public"))
)
return &Negroni{
handlers: handlers,
middleware: build(handlers),
}
// NewRouter 返回一个新的Router实例指针
mx := mux.NewRouter()
return &Router{
namedRoutes: make(map[string]*Route),
KeepContext: false
}
// 为访问的 URL 路径 "/hello/{id}" 匹配一个处理函数
mx.HandleFunc("/hello/{id}", http.HandlerFunc(f)).Methods("GET")
// 让 negroni 使用该 Router
n.UseHandler(mx)
// 返回 negroni 实例
return n
// 指定监听端口为8080
server.Run(":8080")
finalAddr := detectAddress(addr ...) // 返回string
// n 就是 negroni 指针, *negroni 实现了ServeHTTP 方法
http.ListenAndServe(finalAddr, n)
// 此处省略 http.ListenAndServe 的详细流程
n.middleware.ServeHTTP(NewResponseWriter(rw), r)
// 开始一个一个执行中间件, 第三个参数类型为http.HandlerFunc
m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
具体实现:
main.go
package main
import (
"os"
"./service"
flag "github.com/spf13/pflag"
)
const (
PORT string = "8080"
)
func main() {
port := os.Getenv("PORT")
if len(port) == 0 {
port = PORT
}
pPort := flag.StringP("port", "p", PORT, "PORT for httpd listening")
flag.Parse()
if len(*pPort) != 0 {
port = *pPort
}
server := service.NewServer()
server.Run(":" + port)
}
server.go
package service
import (
"net/http"
"github.com/gorilla/mux"
"github.com/unrolled/render"
"github.com/urfave/negroni"
)
// NewServer configures and returns a Server.
func NewServer() *negroni.Negroni {
formatter := render.New(render.Options{
IndentJSON: true,
})
n := negroni.Classic()
mx := mux.NewRouter()
initRoutes(mx, formatter)
n.UseHandler(mx)
return n
}
func initRoutes(mx *mux.Router, formatter *render.Render) {
mx.HandleFunc("/hello/{id}", testHandler(formatter)).Methods("GET")
}
func testHandler(formatter *render.Render) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
id := vars["id"]
formatter.JSON(w, http.StatusOK, struct{ Test string }{"Hello " + id})
}
}
使用 curl 工具访问 web 程序
对 web 执行压力测试