ListenAndServeTLS函数不能android 连接httpss怎么回事

golang(GO语言)http详解简单基础(1) | 微度网络
你的位置: &
& golang(GO语言)http详解简单基础(1)
golang(GO语言)http详解简单基础(1)
因为好像长时间的写PHP可能大家感觉烦躁了,所以写一点golang的东西大家可以拿去玩玩,golang在web开发中让你得心应手,其实也是很好的东西,只要你玩进去之后感觉好爽,感觉比PHP的好处就是没有那么多的“限制”,基础部分大家可以看下简单的我再前边更新了一点点后边会继续给大家补上的,以后就是PHP+golang也可能会写一些object-c的,废话不多说开始写了,所有的代码我放在BUYVM上搭建的GOweb 大家可以去:8080/demo/查看获取完整代码,现在刚弄yaf框架还没有做,大家不用测试攻击玩哈
package main
"net/http"
func hello(rw http.ResponseWriter, req *http.Request) {
io.WriteString(rw, "hello widuu")
func main() {
http.HandleFunc("/", hello)
//设定访问的路径
http.ListenAndServe(":8080", nil) //设定端口和handler
这个我们就输出了hello word,然后我们从源码来解析这个东西,我们看到最后的main函数执行的是HandleFunc这个函数我们从源代码中找到这段的源代码来看如下
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
pattern是解析的路径的字符串,然后执行一个handler的函数方法,如上例子我们传入的hello,他会执行DefaultServeMux,我们在查看源代码的时候会看到var DefaultServeMux = NewServeMux()我们再查看NewServeMux这个源代码
func NewServeMux() *ServeMux {
return &ServeMux{m: make(map[string]muxEntry)}
//而里边的返回一个新的ServeMux
type ServeMux struct {
// contains filtered or unexported fields
所以我们就可以这样字
//申明一个ServeMux结构
type MyHandler struct{}
mux := http.NewServeMux()
//我们可以通过一下 http提供的
func Handle(pattern string, handler Handler)
//第一个是我们的路径字符串 第二个是这样的 是个接口
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
//实现这个接口我们就要继承ServeHTTP这个方法 所以代码
func (*MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "URL"+r.URL.String())
//我们查看源代码
func (mux *ServeMux) Handle(pattern string, handler Handler) //这个新的ServeMux低下的Handle来设置 这里的Handler也是Handler interface所以我们将这个
mux.Handle("/", &MyHandler{})
mux.HandleFunc("/hello", sayHello)// 我们一样可以通过handleFunc设置
//源代码func ListenAndServe(addr string, handler Handler) error
http.ListenAndServe(":8080",mux) //所以我们把mux传进去
//完整代码
package main
"net/http"
type MyHandle struct{}
func main() {
mux := http.NewServeMux()
mux.Handle("/", &MyHandle{})
http.ListenAndServe(":8080", mux)
func (*MyHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "URL"+r.URL.String())
然后我们继续深入点
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
//返回的serve我们查看它的结构
type Server struct {
// TCP address to listen on, ":http" if empty
// handler to invoke, http.DefaultServeMux if nil
ReadTimeout
time.Duration // maximum duration before timing out read of the request
WriteTimeout
time.Duration // maximum duration before timing out write of the response
MaxHeaderBytes int
// maximum size of request headers, DefaultMaxHeaderBytes if 0
*tls.Config
// optional TLS config, used by ListenAndServeTLS
// TLSNextProto optionally specifies a function to take over
// ownership of the provided TLS connection when an NPN
// protocol upgrade has occurred.
The map key is the protocol
// name negotiated. The Handler argument should be used to
// handle HTTP requests and will initialize the Request's TLS
// and RemoteAddr if not already set.
The connection is
// automatically closed when the function returns.
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
//我们自己设置
type MyHandle struct{}
server := http.Server{
&MyHandle{},
ReadTimeout: 6 * time.Second,
//我们查看过了 我们要实现路由分发映射就待这样 我们看到了下边的f 是一个HandlerFunc类型
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
//所以我们申明一下
var mux map[string]func(http.ResponseWriter, *http.Request)
mux = make(map[string]func(http.ResponseWriter, *http.Request))
mux["/hello"] = hello
mux["/bye"] = bye
err := server.ListenAndServe()
if err != nil {
log.Fatal(err)
//这样我们就可以做到了路径的映射
func (*MyHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if h, ok := mux[r.URL.String()]; ok {
io.WriteString(w, "URL"+r.URL.String())
func hello(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "hello 模块")
func bye(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "bye 模块")
//可能有人不懂mux["/hello"] = hello 然后低下的h(w,r) 我简单的解释一下 看个例子 go里边都可以是类型
type test func(int) bool //定一个test的func(int) bool 类型
func isAdd(i int) bool {
if i%2 == 0 {
return false
return true
func filter(s []int, f test) []int {
var result []int
for _, v := range s {
result = append(result, v)
return result
func main() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8}
b := filter(slice, isAdd)
fmt.Println(b)
//是不是懂点了 其实就类似于
f:=func(x int){
fmt.Println("hello")
package main
"net/http"
var mux map[string]func(http.ResponseWriter, *http.Request)
func main() {
server := http.Server{
&MyHandle{},
ReadTimeout: 6 * time.Second,
mux = make(map[string]func(http.ResponseWriter, *http.Request))
mux["/hello"] = hello
mux["/bye"] = bye
err := server.ListenAndServe()
if err != nil {
log.Fatal(err)
type MyHandle struct{}
func (*MyHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if h, ok := mux[r.URL.String()]; ok {
io.WriteString(w, "URL"+r.URL.String())
func hello(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "hello 模块")
func bye(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "bye 模块")
大家不懂的尽管问哈~~时间太晚了有点仓促
转载请注明来自,本文标题:
与本文相关的文章一:首先man.go,整个程序的入口
func main() {
beego.Run()
然后beego.run()代码
// Run beego application.
// beego.Run() default run on HttpPort
// beego.Run(":8089")
// beego.Run("127.0.0.1:8089")
func Run(params ...string) {
if len(params) & 0 && params[0] != "" {
strs := strings.Split(params[0], ":")
if len(strs) & 0 && strs[0] != "" {
HttpAddr = strs[0]
if len(strs) & 1 && strs[1] != "" {
HttpPort, _ = strconv.Atoi(strs[1])
initBeforeHttpRun()
if EnableAdmin {
go beeAdminApp.Run()
BeeApp.Run()
可以看出来,beego.run()可以带参数。
beego.run()在默认的主机、端口号上运行,beego.run(port)在给定的端口号、默认的主机上运行。beego.run(addr:post)在给定的主机和端口上运行。
下面看看initBeforeHttpRun()的代码。
func initBeforeHttpRun() {
// if AppConfigPath not In the conf/app.conf reParse config
if AppConfigPath != filepath.Join(AppPath, "conf", "app.conf") {
err := ParseConfig()
if err != nil && AppConfigPath != filepath.Join(workPath, "conf", "app.conf") {
// configuration is critical to app, panic here if parse failed
panic(err)
// do hooks function
for _, hk := range hooks {
err := hk()
if err != nil {
panic(err)
if SessionOn {
var err error
sessionConfig := AppConfig.String("sessionConfig")
if sessionConfig == "" {
sessionConfig = `{"cookieName":"` + SessionName + `",` +
`"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` +
`"providerConfig":"` + SessionSavePath + `",` +
`"secure":` + strconv.FormatBool(EnableHttpTLS) + `,` +
`"sessionIDHashFunc":"` + SessionHashFunc + `",` +
`"sessionIDHashKey":"` + SessionHashKey + `",` +
`"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` +
`"domain":"` + SessionDomain + `",` +
`"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}`
GlobalSessions, err = session.NewManager(SessionProvider,
sessionConfig)
if err != nil {
panic(err)
go GlobalSessions.GC()
err := BuildTemplate(ViewsPath)
if err != nil {
if RunMode == "dev" {
middleware.VERSION = VERSION
middleware.AppName = AppName
middleware.RegisterErrorHandler()
if EnableDocs {
Get("/docs", serverDocs)
Get("/docs/*", serverDocs)
//init mime
AddAPPStartHook(initMime)
可以看到首先拼凑出来的是conf配置文件的路劲,如果存在然后调用ParseConfig()解析conf。
for _, hk := range hooks {
err := hk()
if err != nil {
panic(err)
hooks的定义
type hookfunc func() error //hook function to run
var hooks []hookfunc
//hook function slice to store the hookfunc
func init() {
hooks = make([]hookfunc, 0)
hooks是一个hookfun的切片,
// The hookfunc will run in beego.Run()
// such as sessionInit, middlerware start, buildtemplate, admin start
func AddAPPStartHook(hf hookfunc) {
hooks = append(hooks, hf)
上面的代码是在启动的时候添加自己的方法hook。也就是hooks是在启动之前,留给用户初始化一些东西的时候。
if SessionOn {
var err error
sessionConfig := AppConfig.String("sessionConfig")
if sessionConfig == "" {
sessionConfig = `{"cookieName":"` + SessionName + `",` +
`"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` +
`"providerConfig":"` + SessionSavePath + `",` +
`"secure":` + strconv.FormatBool(EnableHttpTLS) + `,` +
`"sessionIDHashFunc":"` + SessionHashFunc + `",` +
`"sessionIDHashKey":"` + SessionHashKey + `",` +
`"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` +
`"domain":"` + SessionDomain + `",` +
`"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}`
GlobalSessions, err = session.NewManager(SessionProvider,
sessionConfig)
if err != nil {
panic(err)
go GlobalSessions.GC()
err := BuildTemplate(ViewsPath)
if err != nil {
if RunMode == "dev" {
下面就开始来解析conf文件。如果sessionConfig为空,就使用默认的json数据。然后就开始根据提供的config配置文件创建一个sessionmanager对象
这是session.NewManager()方法的实现
// Create new Manager with provider name and json config string.
// provider name:
// 1. cookie
// 2. file
// 3. memory
// 4. redis
// 5. mysql
// json config:
// 1. is https
default false
// 2. hashfunc
default sha1
// 3. hashkey default beegosessionkey
// 4. maxage default is none
func NewManager(provideName, config string) (*Manager, error) {
provider, ok := provides[provideName]
return nil, fmt.Errorf("session: unknown provide %q (forgotten import?)", provideName)
cf := new(managerConfig)
cf.EnableSetCookie = true
err := json.Unmarshal([]byte(config), cf)
if err != nil {
return nil, err
if cf.Maxlifetime == 0 {
cf.Maxlifetime = cf.Gclifetime
err = provider.SessionInit(cf.Maxlifetime, cf.ProviderConfig)
if err != nil {
return nil, err
if cf.SessionIDHashFunc == "" {
cf.SessionIDHashFunc = "sha1"
if cf.SessionIDHashKey == "" {
cf.SessionIDHashKey = string(generateRandomKey(16))
return &Manager{
可以推测。session.NewManager(SessionProvider,sessionConfig)中SessionProvider是一个全局变量,使用的是在config.go中默认的SessionProvider = "memory",然后改方法返回的是一个Manager的指针对象,即*Manager,所以GlobalSessions是一个*Manager对象。
然后启动一个携程执行GC()方法。下面是GC的源码
// Start session gc process.
// it can do gc in times after gc lifetime.
func (manager *Manager) GC() {
manager.provider.SessionGC()
time.AfterFunc(time.Duration(manager.config.Gclifetime)*time.Second, func() { manager.GC() })
所以上面的代码是一个无限循环,每隔一段time。DUration之后执行GC().
err := BuildTemplate(ViewsPath)
if err != nil {
if RunMode == "dev" {
这里就开始编译模板了。
// build all template files in a directory.
// it makes beego can render any template file in view directory.
func BuildTemplate(dir string) error {
if _, err := os.Stat(dir); err != nil {
if os.IsNotExist(err) {
return nil
return errors.New("dir open err")
self := &templatefile{
files: make(map[string][]string),
err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
return self.visit(path, f, err)
if err != nil {
fmt.Printf("filepath.Walk() returned %v\n", err)
return err
for _, v := range self.files {
for _, file := range v {
t, err := getTemplate(self.root, file, v...)
if err != nil {
Trace("parse template err:", file, err)
BeeTemplates[file] = t
return nil
首先判断目录是否存在。目录ViewsPath在config中有初始化。然后初始化templatefile结构体,filepath.Walk()走一边目录里的文件,记录在self.files里面。循环self.files中的file(map[dir][]file]),用getTemplate获取template.Template实例,保存在beego.BeeTemplates(map[string]template.Template)。
middleware.VERSION = VERSION
middleware.AppName = AppName
middleware.RegisterErrorHandler()
if EnableDocs {
Get("/docs", serverDocs)
Get("/docs/*", serverDocs)
//init mime
AddAPPStartHook(initMime)
middleware包括的是错误处理的功能。如NotFound()、Forbidden()、Errorhandler()等等处理。。
随后的AddAPPStartHook(initMine)则是初始化所有的minetype类型的函数。
上面的代码实在beego项目启动前需要操作的比如初始化conf配置、编译模板文件、注册错误处理中间件、加载所有的mimetype类型、
然后继续回到beego.run()代码中间
if EnableAdmin {
go beeAdminApp.Run()
BeeApp.Run()
很简单。如果beego允许admin。则执行beeAdminApp。beeAdminApp也是一个*beego.adminApp,负责系统监控、性能检测、访问统计和健康检查等。然后猪线程运行BeeApp.Run()方法,开始执行beego。
下面看看beego.adminApp的代码
// adminApp is an http.HandlerFunc map used as beeAdminApp.
type adminApp struct {
routers map[string]http.HandlerFunc
// Route adds http.HandlerFunc to adminApp with url pattern.
func (admin *adminApp) Route(pattern string, f http.HandlerFunc) {
admin.routers[pattern] = f
// Run adminApp http server.
// Its addr is defined in configuration file as adminhttpaddr and adminhttpport.
func (admin *adminApp) Run() {
if len(toolbox.AdminTaskList) & 0 {
toolbox.StartTask()
addr := AdminHttpAddr
if AdminHttpPort != 0 {
addr = fmt.Sprintf("%s:%d", AdminHttpAddr, AdminHttpPort)
for p, f := range admin.routers {
http.Handle(p, f)
err := http.ListenAndServe(addr, nil)
if err != nil {
BeeLogger.Critical("Admin ListenAndServe: ", err)
// task interface
type Tasker interface {
GetStatus() string
Run() error
SetNext(time.Time)
GetNext() time.Time
SetPrev(time.Time)
GetPrev() time.Time
AdminTaskList map[string]Tasker
// start all tasks
func StartTask() {
isstart = true
func run() {
now := time.Now().Local()
for _, t := range AdminTaskList {
t.SetNext(now)
sortList := NewMapSorter(AdminTaskList)
sortList.Sort()
var effective time.Time
if len(AdminTaskList) == 0 || sortList.Vals[0].GetNext().IsZero() {
// If there are no entries yet, just sleep - it still handles new entries
// and stop requests.
effective = now.AddDate(10, 0, 0)
effective = sortList.Vals[0].GetNext()
case now = &-time.After(effective.Sub(now)):
// Run every entry whose next time was this effective time.
for _, e := range sortList.Vals {
if e.GetNext() != effective {
go e.Run()
e.SetPrev(e.GetNext())
e.SetNext(effective)
case &-changed:
case &-stop:
// start all tasks
func StopTask() {
isstart = false
stop &- true
// add task with name
func AddTask(taskname string, t Tasker) {
AdminTaskList[taskname] = t
if isstart {
changed &- true
// add task with name
func DeleteTask(taskname string) {
delete(AdminTaskList, taskname)
if isstart {
changed &- true
adminApp结构体里面只有map结构的router,toolbox.AdminTaskList是一个map类型的结构。如果AdminTaskList中间有Tasker。则开始执行StartTask(),而且,StartTask()方法中实现的是另外打开一个协程执行Run()方法。最后打开http.ListenAndServe()实现监听。
下面是BeeApp.Run()
package beego
"net/http"
"net/http/fcgi"
"/astaxie/beego/context"
// FilterFunc defines filter function type.
type FilterFunc func(*context.Context)
// App defines beego application with a new PatternServeMux.
type App struct {
Handlers *ControllerRegistor
*http.Server
// NewApp returns a new beego application.
func NewApp() *App {
cr := NewControllerRegister()
app := &App{Handlers: cr, Server: &http.Server{}}
return app
// Run beego application.
func (app *App) Run() {
addr := HttpAddr
if HttpPort != 0 {
addr = fmt.Sprintf("%s:%d", HttpAddr, HttpPort)
("Running on %s", addr)
net.Listener
endRunning := make(chan bool, 1)
if UseFcgi {
if HttpPort == 0 {
l, err = net.Listen("unix", addr)
l, err = net.Listen("tcp", addr)
if err != nil {
BeeLogger.Critical("Listen: ", err)
err = fcgi.Serve(l, app.Handlers)
app.Server.Addr = addr
app.Server.Handler = app.Handlers
app.Server.ReadTimeout = time.Duration(HttpServerTimeOut) * time.Second
app.Server.WriteTimeout = time.Duration(HttpServerTimeOut) * time.Second
if EnableHttpTLS {
go func() {
time.Sleep(20 * time.Microsecond)
if HttpsPort != 0 {
app.Server.Addr = fmt.Sprintf("%s:%d", HttpAddr, HttpsPort)
err := app.Server.ListenAndServeTLS(HttpCertFile, HttpKeyFile)
if err != nil {
BeeLogger.Critical("ListenAndServeTLS: ", err)
time.Sleep(100 * time.Microsecond)
endRunning &- true
if EnableHttpListen {
go func() {
app.Server.Addr = addr
err := app.Server.ListenAndServe()
if err != nil {
BeeLogger.Critical("ListenAndServe: ", err)
time.Sleep(100 * time.Microsecond)
endRunning &- true
&-endRunning
上面的代码首先是获取地址addr,然后执行fast-cgi,调用ListenAndServeTLS监听cgi服务,后面的是Http服务,调用ListenAndServe()监听http服务。
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections.
// srv.Addr is blank, ":http" is used.
func (srv *Server) ListenAndServe() error {
addr := srv.Addr
if addr == "" {
addr = ":http"
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
// Serve accepts incoming connections on the Listener l, creating a
// new service goroutine for each.
The service goroutines read requests and
// then call srv.Handler to reply to them.
func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
var tempDelay time.Duration // how long to sleep on accept failure
rw, e := l.Accept()
if e != nil {
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
tempDelay *= 2
if max := 1 * time.S tempDelay & max {
tempDelay = max
srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
tempDelay = 0
c, err := srv.newConn(rw)
if err != nil {
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve()
ListenAndServe()的功能:
1、初始化一个Server
2、调用Server的ListenAndServe()
3、调用net.Listen(&tcp&, addr)监听端口
4、启动一个for循环,在循环体中Accept请求
5、对每个请求实例化一个Conn,并且开启一个goroutine为这个请求进行服务go c.serve()
下面看看进入c.serve()方法的源码
// Serve a new connection.
func (c *conn) serve() {
origConn := c.rwc // copy it before it's set nil on Close or Hijack
defer func() {
if err := recover(); err != nil {
const size = 64 && 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
if !c.hijacked() {
c.setState(origConn, StateClosed)
if tlsConn, ok := c.rwc.(*tls.Conn); ok {
if d := c.server.ReadT d != 0 {
c.rwc.SetReadDeadline(time.Now().Add(d))
if d := c.server.WriteT d != 0 {
c.rwc.SetWriteDeadline(time.Now().Add(d))
if err := tlsConn.Handshake(); err != nil {
c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)
c.tlsState = new(tls.ConnectionState)
*c.tlsState = tlsConn.ConnectionState()
if proto := c.tlsState.NegotiatedP validNPN(proto) {
if fn := c.server.TLSNextProto[proto]; fn != nil {
h := initNPNRequest{tlsConn, serverHandler{c.server}}
fn(c.server, tlsConn, h)
w, err := c.readRequest()
if c.lr.N != c.server.initialLimitedReaderSize() {
// If we read any bytes off the wire, we're active.
c.setState(c.rwc, StateActive)
if err != nil {
if err == errTooLarge {
// Their HTTP client may or may not be
// able to read this if we're
// responding to them and hanging up
// while they're still writing their
// request.
Undefined behavior.
io.WriteString(c.rwc, "HTTP/1.1 413 Request Entity Too Large\r\n\r\n")
c.closeWriteAndWait()
} else if err == io.EOF {
break // Don't reply
} else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
break // Don't reply
io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\n\r\n")
// Expect 100 Continue support
req := w.req
if req.expectsContinue() {
if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
// Wrap the Body reader with one that replies on the connection
req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
req.Header.Del("Expect")
} else if req.Header.get("Expect") != "" {
w.sendExpectationFailed()
// HTTP cannot have multiple simultaneous active requests.[*]
// Until the server replies to this request, it can't read another,
// so we might as well run the handler in this goroutine.
// [*] Not strictly true: HTTP pipelining.
We could let them all process
// in parallel even if their responses need to be serialized.
serverHandler{c.server}.ServeHTTP(w, w.req)
if c.hijacked() {
w.finishRequest()
if w.closeAfterReply {
if w.requestBodyLimitHit {
c.closeWriteAndWait()
c.setState(c.rwc, StateIdle)
上面的代码实现:
1、读取每个请求的内容w, err := c.readRequest()
2、判断handler是否为空,如果没有设置handler(这个例子就没有设置handler),handler就设置为DefaultServeMux
3、调用handler的ServeHttp
4、根据request选择handler,并且进入到这个handler的ServeHTTP
5、选择handler
&下面就开始Http请求的过程了。上文中提到的handler在beego项目中就是beego.ControllerRegistor结构体,下面是ControllerRegistor的源码。可以看见。实现了http.handler接口的ServeHTTP方法。而且,上下文对象context也被初始化了。后面的do_filter就是实现过滤方法的实现。然后就是判断请求的方法、seesion等函数。
而且还有一个很重要的就是runrouter、runMethod、findrouter、routerInfo这四个参数,在方法开头就已经定义了。
// ControllerRegistor containers registered router rules, controller handlers and filters.
type ControllerRegistor struct {
map[string]*Tree
enableFilter bool
map[int][]*FilterRouter
// Implement http.Handler interface.
func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
defer p.recoverPanic(rw, r)
starttime := time.Now()
var runrouter reflect.Type
var findrouter bool
var runMethod string
var routerInfo *controllerInfo
w := &responseWriter{writer: rw}
if RunMode == "dev" {
w.Header().Set("Server", BeegoServerName)
// init context
context := &beecontext.Context{
ResponseWriter: w,
beecontext.NewInput(r),
beecontext.NewOutput(),
context.Output.Context = context
context.Output.EnableGzip = EnableGzip
// defined filter function
do_filter := func(pos int) (started bool) {
if p.enableFilter {
if l, ok := p.filters[pos]; ok {
for _, filterR := range l {
if ok, p := filterR.ValidRouter(r.URL.Path); ok {
context.Input.Params = p
filterR.filterFunc(context)
if w.started {
return true
return false
// filter wrong httpmethod
if _, ok := HTTPMETHOD[r.Method]; !ok {
http.Error(w, "Method Not Allowed", 405)
goto Admin
// filter for static file
if do_filter(BeforeStatic) {
goto Admin
serverStaticRouter(context)
if w.started {
findrouter = true
goto Admin
// session init
if SessionOn {
context.Input.CruSession = GlobalSessions.SessionStart(w, r)
defer func() {
context.Input.CruSession.SessionRelease(w)
if r.Method != "GET" && r.Method != "HEAD" {
if CopyRequestBody && !context.Input.IsUpload() {
context.Input.CopyBody()
context.Input.ParseFormOrMulitForm(MaxMemory)
if do_filter(BeforeRouter) {
goto Admin
if context.Input.RunController != nil && context.Input.RunMethod != "" {
findrouter = true
runMethod = context.Input.RunMethod
runrouter = context.Input.RunController
if !findrouter {
if t, ok := p.routers[r.Method]; ok {
runObject, p := t.Match(r.URL.Path)
if r, ok := runObject.(*controllerInfo); ok {
routerInfo = r
findrouter = true
if splat, ok := p[":splat"]; ok {
splatlist := strings.Split(splat, "/")
for k, v := range splatlist {
p[strconv.Itoa(k)] = v
context.Input.Params = p
//if no matches to url, throw a not found exception
if !findrouter {
middleware.Exception("404", rw, r, "")
goto Admin
if findrouter {
//execute middleware filters
if do_filter(BeforeExec) {
goto Admin
isRunable := false
if routerInfo != nil {
if routerInfo.routerType == routerTypeRESTFul {
if _, ok := routerInfo.methods[r.Method]; ok {
isRunable = true
routerInfo.runfunction(context)
middleware.Exception("405", rw, r, "Method Not Allowed")
goto Admin
} else if routerInfo.routerType == routerTypeHandler {
isRunable = true
routerInfo.handler.ServeHTTP(rw, r)
runrouter = routerInfo.controllerType
method := r.Method
if r.Method == "POST" && context.Input.Query("_method") == "PUT" {
method = "PUT"
if r.Method == "POST" && context.Input.Query("_method") == "DELETE" {
method = "DELETE"
if m, ok := routerInfo.methods[method]; ok {
runMethod = m
} else if m, ok = routerInfo.methods["*"]; ok {
runMethod = m
runMethod = method
// also defined runrouter & runMethod from filter
if !isRunable {
//Invoke the request handler
vc := reflect.New(runrouter)
execController, ok := vc.Interface().(ControllerInterface)
panic("controller is not ControllerInterface")
//call the controller init function
execController.Init(context, runrouter.Name(), runMethod, vc.Interface())
//call prepare function
execController.Prepare()
//if XSRF is Enable then check cookie where there has any cookie in the
request's cookie _csrf
if EnableXSRF {
execController.XsrfToken()
if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" ||
(r.Method == "POST" && (context.Input.Query("_method") == "DELETE" || context.Input.Query("_method") == "PUT")) {
execController.CheckXsrfCookie()
execController.URLMapping()
if !w.started {
//exec main logic
switch runMethod {
case "GET":
execController.Get()
case "POST":
execController.Post()
case "DELETE":
execController.Delete()
case "PUT":
execController.Put()
case "HEAD":
execController.Head()
case "PATCH":
execController.Patch()
case "OPTIONS":
execController.Options()
if !execController.HandlerFunc(runMethod) {
in := make([]reflect.Value, 0)
method := vc.MethodByName(runMethod)
method.Call(in)
//render template
if !w.started && context.Output.Status == 0 {
if AutoRender {
if err := execController.Render(); err != nil {
panic(err)
// finish all runrouter. release resource
execController.Finish()
//execute middleware filters
if do_filter(AfterExec) {
goto Admin
do_filter(FinishRouter)
timeend := time.Since(starttime)
//admin module record QPS
if EnableAdmin {
if FilterMonitorFunc(r.Method, r.URL.Path, timeend) {
if runrouter != nil {
go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, runrouter.Name(), timeend)
go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, "", timeend)
if RunMode == "dev" {
var devinfo string
if findrouter {
if routerInfo != nil {
devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s | % -40s |", r.Method, r.URL.Path, timeend.String(), "match", routerInfo.pattern)
devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "match")
devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "notmatch")
Debug(devinfo)
// Call WriteHeader if status code has been set changed
if context.Output.Status != 0 {
w.writer.WriteHeader(context.Output.Status)
下面开始看看路由的调用,上面代码中的
if findrouter {
//execute middleware filters
if do_filter(BeforeExec) {
goto Admin
isRunable := false
if routerInfo != nil {
if routerInfo.routerType == routerTypeRESTFul {
if _, ok := routerInfo.methods[r.Method]; ok {
isRunable = true
routerInfo.runfunction(context)
middleware.Exception("405", rw, r, "Method Not Allowed")
goto Admin
} else if routerInfo.routerType == routerTypeHandler {
isRunable = true
routerInfo.handler.ServeHTTP(rw, r)
runrouter = routerInfo.controllerType
method := r.Method
if r.Method == "POST" && context.Input.Query("_method") == "PUT" {
method = "PUT"
if r.Method == "POST" && context.Input.Query("_method") == "DELETE" {
method = "DELETE"
if m, ok := routerInfo.methods[method]; ok {
runMethod = m
} else if m, ok = routerInfo.methods["*"]; ok {
runMethod = m
runMethod = method
首先是do_filter(BeforeExec)进入go Admin,执行控制器方法前面的过滤。然后vc := reflect.New(runrouter)创建一个控制器实例。最后在执行do_filter(AfterExec)过滤器方法。在execController.Init(context, runrouter.Name(), runMethod, vc.Interface())里面实现了初始化controller的方法。每次请求都会不相同。
最后在下面的代码
if !w.started {
//exec main logic
switch runMethod {
case "GET":
execController.Get()
case "POST":
execController.Post()
case "DELETE":
execController.Delete()
case "PUT":
execController.Put()
case "HEAD":
execController.Head()
case "PATCH":
execController.Patch()
case "OPTIONS":
execController.Options()
if !execController.HandlerFunc(runMethod) {
in := make([]reflect.Value, 0)
method := vc.MethodByName(runMethod)
method.Call(in)
按照不同的求情方式请求不同的方法。默认的是根据反射。然后method.call()来调用。实现了router的路由注册。。
终于写完了。其实我也不知道自己写的是什么。过几天再改进。。待续。。。。
阅读(...) 评论()}

我要回帖

更多关于 https 长连接 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信