任务目标
- 熟悉 go 服务器工作原理
- 基于现有 web 库,编写一个简单 web 应用类似 cloudgo
- 使用 curl 工具访问 web 程序
- 对 web 执行压力测试
- 根据代码提示,按照
cloud_go
应用,编写相应的Web
程序。 - main.go
- 按照
flag
包的应用,从命令行获取特定的端口号,默认为8080
,并获取web
服务,调用Run
对特定端口开启特定服务,相应代码如下:
const ( PORT string = "8080" ) func main() { port := os.Getenv("PORT")//get custom environment variables if len(port) == 0 { port = PORT } flag.StringVar(&port, "p", PORT, "PORT for httpd listening") flag.Parse() server := service.NewServer() // get server server.Run(":" + port) // run the server at specific port }
- 按照
- server.go
- 该
go
文件函数NewServer
提供main.go
创建相应的web
服务。 - 调用
render.New()
函数为相应的web
服务渲染格式,此处只简单的设置IndentJSON
格式,后分别调用negroni.Classic
和mux.NewRouter
,以默认参数创建web
服务对象和Router
路由对象。
func NewServer() *negroni.Negroni { // New constructs a new Render instance with the supplied options. formatter := render.New(render.Options{ IndentJSON: true, }) // rendering a web format n := negroni.Classic() mx := mux.NewRouter() initRoutes(mx, formatter) // set the router n.UseHandler(mx) return n }
- 其上的
initRoutes
函数负责设置路由配置,主要是按照不同的路由提供不同的服务,其中包含通过变量名获取参数信息如通过对http.Request
调用URL
处理获取特定信息,也如通过Methods
方法获取形如{id}
对应的变量值。其中,对路由调用HandleFunc
设置不同路由特定的函数操作,需要传入func(w http.ResponseWriter, req *http.Request)
形式的函数处理。
func initRoutes(mx *mux.Router, formatter *render.Render) { // Methods adds a matcher for HTTP methods. // It accepts a sequence of one or more methods to be matched, e.g.: // "GET", "POST", "PUT". mx.HandleFunc("/{status}/{id}", testHandler(formatter)).Methods("GET") mx.HandleFunc("/{status}", testHandler(formatter)).Methods("GET") //provide a hanlder func to deal with specific router //corresponding to func(w http.ResponseWriter, req *http.Request) }
- 根据传入的路由形式,我们可以获取处理的
localhost:9090/xxx
以及localhost:9090/xxx/yyy
形式的路由并获取对应的参数值。通过形如map[string] string
的方式输入对应的xxx
或yyy
即可获取对应的参数。此处再调用render.JSON
函数对http.ResponseWriter
处理,再其上输出文本信息,即如下即可。
func testHandler(formatter *render.Render) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) id := vars["id"] status := vars["status"] formatter.JSON(w, http.StatusOK, struct{ Test string }{"Hello " + status + id}) } }
- 该
- 测试
- 在
linux
系统上调用curl -v http://www.sysu.edu.cn/
访问网址,根据输出内容可以看出- 以
*
为首的信息为curl
程序的操作内容 - 以
>
为首的信息为发送到指定网址的内容 - 以
<
为首的信息为指定网址返回的内容
- 以
- 以上述代码运行后输入
http://localhost:9090/hello
时,对应路由信息为/{status}
,即status
对应hello,id
为空,输出内容如下: - 输入
http://localhost:9090/hello/world
时,status
对应hello,id
为对应world,输出内容如下: - 修改代码,去掉对路由
/{status}
的处理后再次输入http://localhost:9090/hello
,输出内容如下,可以发现报错404
,此时可以认为设置路由时需要处理不同层次的内容,上级路由与下级路由之间不能互通。 - 此时,通过
Apache
软件对服务进行压力测试,输入指令ab -n 1000 -c 100 http://localhost:9090/hello/world
,输出如下结果,其中左侧为链接网络消耗的时间等信息,右侧为测试后的结果,通过对信息的分析可以了解到连接的速度以及网址访问的相关信息。
- 在