问题描述
我正在Golang(初学者)学习Web开发,遇到了一些我玩过的代码,但我不太确定为什么会起作用,我浏览了库的源代码和文档,但我只有一个模糊的主意仍然没有点击.请注意以下代码:
I am studying web development in Golang (Beginner) I came across some code I played around with and I'm not too sure why it works, I looked through the library source code and docs but I only have a vague idea it still isn't clicking. Note the code below:
package main
import (
"fmt"
"net/http"
)
type foo int
func (m foo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Some text")
}
func main() {
var bar foo
http.ListenAndServe(":8080", bar)
}
据我了解,添加 ServeHTTP(w http.ResponseWriter,r * http.Request)作为函数方法,会调用 handler接口(如果我说的是正确),现在 foo 也是类型处理程序.我还了解到 http.ListenAndServe 接受类型处理程序的输入,因此这就是我的变量 bar 起作用的地方.当我运行代码并在浏览器上转到localhost:8080时,出现"Some Text".
From what I understand adding ServeHTTP(w http.ResponseWriter, r *http.Request) as a function method, invokes the handler interface (if I'm saying that correctly) and now foo is of type handler as well. I also understand that http.ListenAndServe takes an input of type handler so that is where my variable bar comes into play. When I run the code and go to localhost:8080 on my browser I get "Some Text" appearing.
实现界面是不调用的正确术语.
Implements the interface is the proper term NOT invoke.
问题:
这是如何工作的?如何访问ServeHTTP函数?
我尝试查看这些库的源代码,但无法确切指出ServeHTTP的工作方式.我发现这两段代码(不确定是否适用)让我觉得它正在实现一个函数,但需要澄清一下:
I tried looking at the source code of the libraries but couldn't pinpoint exactly how ServeHTTP worked. I found these two pieces of code (not sure if this is applicable) that sort of gave me the idea it was implementing a function but need clarification:
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
我从未见过像HandlerFunc那样的类型声明,该声明在类型名称之后具有功能.我还看到了如何声明方法,但不确定上面的代码中发生了什么.
I have never seen a type declaration as the one above with HandlerFunc that has a function after the name of the type. I have also seen how methods are declared but not sure what is happening in the code above.
推荐答案
这是如何工作的?如何访问ServeHTTP函数?
要回答此问题,我们需要查看http.ListenAndServe
的工作方式:
To answer this question we need to look how http.ListenAndServe
works:
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
在这里,我们创建一个具有给定地址和处理程序的服务器,并调用ListenAndServer方法,让我们看一下那里:
Here we create a Server with given address and handler and call the ListenAndServer method so let's take a look there:
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)})
}
此方法只是开始侦听给定的地址,并使用我们新创建的侦听器调用Server方法,所以让我们按照那里的方法进行操作:
This method just starts listening given address and calls the Server method with our freshly created listener so let's follow the trail there:
func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
...
for {
rw, e := l.Accept()
...
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve(ctx)
}
}
从Serve方法中可以看到,这是我们接受新连接并开始在其自己的goroutine中对其进行处理的地方.
From the Serve method we can see that this is the point where we accept the new connection and start handling it in it's own goroutine.
// Serve a new connection.
func (c *conn) serve(ctx context.Context) {
...
for {
w, err := c.readRequest(ctx)
...
serverHandler{c.server}.ServeHTTP(w, w.req)
...
}
}
在这里,我们最终调用ServeHTTP方法,但是正如我们看到的那样,这不是我们对该函数的实现,而是标准库中的内容,因此让我们看一下serverHandler结构包含的内容:
Here we finally call the ServeHTTP method but as we can see this is not yet our implementation of that function but something from the standard library so let's take a look what that serverHandler struct contains:
// serverHandler delegates to either the server's Handler or
// DefaultServeMux and also handles "OPTIONS *" requests.
type serverHandler struct {
srv *Server
}
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler := sh.srv.Handler
if handler == nil {
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
handler.ServeHTTP(rw, req)
}
所以终于到了.如果我们不提供任何处理程序,则将使用DefaultServeMux,但由于我们提供了foo处理程序,因此从foo get调用了ServeHTTP.
So here it is finally. If we didn't provide any Handler the DefaultServeMux will be used but since we provided our foo handler ServeHTTP from foo get's called.
就是这样.所有这些都可以在 server.go
And that's it. All of this can be found from server.go
这篇关于ServeHTTP如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!