简单的 Go 网络服务器,在客户端看不到响应

我正在学习 Go,并且正在编写一个简单的 Web 服务器,它使用一个通道来限制并发请求的数量。服务器在控制台打印日志条目,显示它正在接收请求并处理它们,但是客户端浏览器不显示任何输出。我试过添加响应编写器的冲洗,但没有帮助。


作为菜鸟,我错过了什么?感谢您提供任何提示/指示。


这是代码:


package main


import (

    "fmt"

    "html"

    "net/http"

    "time"

)


// define a type to be used with our request channel

type clientRequest struct {

    r *http.Request

    w http.ResponseWriter

}


const (

    MaxRequests int = 10

)


// the request channel, to limit the number of simultaneous requests being processed

var reqChannel chan *clientRequest


func init() {

    reqChannel = make(chan *clientRequest, MaxRequests)

}


func main() {

    // create the server's handler

    var ServeMux = http.NewServeMux()

    ServeMux.HandleFunc("/", serveHandler)


    // start pool of request handlers, all reading from the same channel

    for i := 0; i < MaxRequests; i++ {

        go processRequest(i)

    }


    // create the server object

    s := &http.Server{

        Addr:           ":8080",

        Handler:        ServeMux,         // handler to invoke, http.DefaultServeMux if nil

        ReadTimeout:    10 * time.Second, // maximum duration before timing out read of the request

        WriteTimeout:   10 * time.Second, // maximum duration before timing out write of the response

        MaxHeaderBytes: 1 << 20,          // maximum size of request headers, 1048576 bytes

    }


    // start the server

    err := s.ListenAndServe()

    if err != nil {

        fmt.Println("Server failed to start: ", err)

    }

}


func serveHandler(w http.ResponseWriter, r *http.Request) {

    var newRequest = new(clientRequest)

    newRequest.r = r

    newRequest.w = w


    reqChannel <- newRequest // send the new request to the request channel

    fmt.Printf("Sent request to reqChannel for URL: %q\n", html.EscapeString(r.URL.Path))

}



慕田峪7331174
浏览 248回答 2
2回答

ibeautiful

服务器在serveHandler返回时关闭响应。一种解决方法是阻塞serveHandler直到请求被处理。在以下代码中,worker 关闭done以表示请求已完成。处理程序等待done关闭。type clientRequest struct {&nbsp; &nbsp; r *http.Request&nbsp; &nbsp; w http.ResponseWriter&nbsp; &nbsp; done chan struct{}&nbsp; // <-- add this line}func serveHandler(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp;var newRequest = new(clientRequest)&nbsp; &nbsp;newRequest.r = r&nbsp; &nbsp;newRequest.w = w&nbsp; &nbsp;newRequest.done = make(chan struct{})&nbsp; &nbsp;reqChannel <- newRequest // send the new request to the request channel&nbsp; &nbsp;fmt.Printf("Sent request to reqChannel for URL: %q\n", html.EscapeString(r.URL.Path))&nbsp; &nbsp;<-newRequest.done&nbsp; // wait for worker goroutine to complete}func processRequest(instanceNbr int) {&nbsp; &nbsp;fmt.Printf("processRequest started for instance #%d\n", instanceNbr)&nbsp; &nbsp;for theRequest := range reqChannel { // receive requests from the channel until it is closed&nbsp; &nbsp; &nbsp; &nbsp;fmt.Printf("Got request from reqChannel for URL: %q\n", html.EscapeString(theRequest.r.URL.Path))&nbsp; &nbsp; &nbsp; &nbsp;fmt.Fprintf(theRequest.w, "processRequest instance #%d: URL is %q", instanceNbr, html.EscapeString(theRequest.r.URL.Path))&nbsp; &nbsp; &nbsp; &nbsp;if f, ok := theRequest.w.(http.Flusher); ok {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;f.Flush()&nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp; &nbsp;close(theRequest.done)&nbsp; // signal handler that request is complete&nbsp; &nbsp;}}如果目标是限制活动处理程序的数量,那么您可以使用通道作为计数信号量来限制活动处理程序 goroutine 的数量:var reqChannel = make(chan struct{}, MaxRequests)func serveHandler(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; reqChannel <- struct{}{}&nbsp;&nbsp; &nbsp; // handle the request&nbsp; &nbsp; <-reqChannel}请注意,服务器在每个连接的 goroutine 中运行处理程序。更简单的是只编写一个处理程序。大多数服务器不需要限制请求处理程序的并发性。

慕的地6264312

您的答案在net/http 代码的这一部分:&nbsp; &nbsp; // HTTP cannot have multiple simultaneous active requests.[*]&nbsp; &nbsp; // Until the server replies to this request, it can't read another,&nbsp; &nbsp; // so we might as well run the handler in this goroutine.&nbsp; &nbsp; // [*] Not strictly true: HTTP pipelining.&nbsp; We could let them all process&nbsp; &nbsp; // in parallel even if their responses need to be serialized.&nbsp; &nbsp; serverHandler{c.server}.ServeHTTP(w, w.req)&nbsp; &nbsp; if c.hijacked() {&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; w.finishRequest()后ServeHTTP返回时,请求完成。所以你有几个解决方案:放弃你的工人模式并完成工作 serveHandler在完成之前等待请求被完全处理serveHandler,如下所示:(在我的本地测试)type clientRequest struct {&nbsp; &nbsp; r *http.Request&nbsp; &nbsp; w http.ResponseWriter&nbsp; &nbsp; done chan struct{}}func serveHandler(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; var newRequest = new(clientRequest)&nbsp; &nbsp; newRequest.r = r&nbsp; &nbsp; newRequest.w = w&nbsp; &nbsp; newRequest.done = make(chan struct{})&nbsp; &nbsp; reqChannel <- newRequest // send the new request to the request channel&nbsp; &nbsp; fmt.Printf("Sent request to reqChannel for URL: %q\n", html.EscapeString(r.URL.Path))&nbsp; &nbsp; <-newRequest.done // wait for the worker to finish}func processRequest(instanceNbr int) {&nbsp; &nbsp; fmt.Printf("processRequest started for instance #%d\n", instanceNbr)&nbsp; &nbsp; for theRequest := range reqChannel { // receive requests from the channel until it is closed&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("Got request from reqChannel for URL: %q\n", html.EscapeString(theRequest.r.URL.Path))&nbsp; &nbsp; &nbsp; &nbsp; // xxx this isn't working:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Fprintf(theRequest.w, "processRequest instance #%d: URL is %q", instanceNbr, html.EscapeString(theRequest.r.URL.Path))&nbsp; &nbsp; &nbsp; &nbsp; if f, ok := theRequest.w.(http.Flusher); ok {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f.Flush()&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; theRequest.done <- struct{}{}&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go