使用net/http包快速创建一个HTTP服务器。
// file http_test1.go
package main
import (
@H_301_5@"fmt"
@H_301_5@"net/http"
@H_301_5@"log"
)
func HandleIndex(w http.ResponseWriter,r *http.Request) {
r.ParseForm()
fmt.Println(@H_301_5@"PATH: ",r.URL.Path)
fmt.Println(@H_301_5@"SCHEME: ",r.URL.Scheme)
fmt.Println(@H_301_5@"METHOD: ",r.Method)
fmt.Println()
fmt.Fprintf(w,@H_301_5@"<h1>Index Page</h1>")
}
func main() {
http.HandleFunc(@H_301_5@"/",HandleIndex)
err := http.ListenAndServe(@H_301_5@":8000",nil)
if err != nil {
log.Fatal(@H_301_5@"ERROR: ",err)
}
}
其实有时候语言无关紧要,原理大抵相同。此handler就如同Python的WSGI协议application(environ,start_response)
,如同Nodejs的callback(req,res)
函数。并且他们底层都是基于socket(好像是的!!!)
$ go run http_test1.go
在浏览器中输入127.0.0.1:8000可以看到浏览器显示:
在终端上打印出如下信息:
虽然我们没有像其他语言一样显式地监听端口,启动服务器,或者用socket来搭建tcp或udp服务器,用while循环来获取请求数据。但是我们不难发现服务的入口在http.ListenAndServe
。我们来看一下源码,探讨它究竟做了什么工作。
$ godoc -src net/http ListenAndServe
会打印出来两个相似的函数:
func (srv *Server) ListenAndServe() error {
addr := srv.Addr
if addr == @H_301_5@"" {
addr = @H_301_5@":http"
}
ln,err := net.Listen(@H_301_5@"tcp",addr)
if err != nil {
return err
}
return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}
func ListenAndServe(addr string,handler Handler) error {
server := &Server{Addr: addr,Handler: handler}
return server.ListenAndServe()
}
不要觉得这两个同名的函数像C++或Java一样是重载函数,Go语言中是没有函数签名这个概念的。
第一个函数func (srv *Server) ListenAndServe() error
,这是type Server struct
类型的一个方法,你可以理解为面向对象中的方法,属于Server类。
而第二个函数func ListenAndServe(addr string,handler Handler) error
则是一个普通函数,内部进行封装,更简洁地实现HTTP服务器。你可以看到它创建了Server类的一个对象,然后调用了刚才说的第一个函数。