首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >简单的Go web服务器,在客户端看不到响应

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

Stack Overflow用户
提问于 2015-10-14 01:00:25
回答 2查看 1.2K关注 0票数 2

我正在学习Go,并且正在编写一个简单的web服务器,它使用一个通道来限制并发请求的数量。服务器在控制台上打印日志条目,显示它正在接收和处理请求,但是客户端浏览器没有显示任何输出。我试过添加一个同花顺的回复作者,这没有帮助。

作为一个菜鸟,我错过了什么?谢谢你的提示/指点。

下面是代码:

代码语言:javascript
复制
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))
}

func processRequest(instanceNbr int) {
    fmt.Printf("processRequest started for instance #%d\n", instanceNbr)
    for theRequest := range reqChannel { // receive requests from the channel until it is closed
        fmt.Printf("Got request from reqChannel for URL: %q\n", html.EscapeString(theRequest.r.URL.Path))

        // xxx this isn't working:
        fmt.Fprintf(theRequest.w, "processRequest instance #%d: URL is %q", instanceNbr, html.EscapeString(theRequest.r.URL.Path))
        if f, ok := theRequest.w.(http.Flusher); ok {
            f.Flush()
        }
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-10-14 01:21:56

serveHandler返回时,服务器将关闭响应。

一个解决方法是阻止serveHandler,直到请求被处理为止。在以下代码中,工作人员关闭done以发出请求已完成的信号。处理程序等待done关闭。

代码语言:javascript
复制
type clientRequest struct {
    r *http.Request
    w http.ResponseWriter
    done chan struct{}  // <-- add this line
}

func serveHandler(w http.ResponseWriter, r *http.Request) {
   var newRequest = new(clientRequest)
   newRequest.r = r
   newRequest.w = w
   newRequest.done = make(chan struct{})

   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))
   <-newRequest.done  // wait for worker goroutine to complete
}

func processRequest(instanceNbr int) {
   fmt.Printf("processRequest started for instance #%d\n", instanceNbr)
   for theRequest := range reqChannel { // receive requests from the channel until it is closed
       fmt.Printf("Got request from reqChannel for URL: %q\n", html.EscapeString(theRequest.r.URL.Path))

       fmt.Fprintf(theRequest.w, "processRequest instance #%d: URL is %q", instanceNbr, html.EscapeString(theRequest.r.URL.Path))
       if f, ok := theRequest.w.(http.Flusher); ok {
           f.Flush()
       }
       close(theRequest.done)  // signal handler that request is complete
   }
}

如果目标是限制活动处理程序的数量,那么可以使用一个通道作为计数信号量来限制活动处理程序goroutines的数量:

代码语言:javascript
复制
var reqChannel = make(chan struct{}, MaxRequests)

func serveHandler(w http.ResponseWriter, r *http.Request) {
    reqChannel <- struct{}{} 
    // handle the request
    <-reqChannel
}

请注意,服务器在每个连接goroutine中运行处理程序。

更简单的是只编写一个处理程序。大多数服务器不需要限制请求处理程序的并发性。

票数 3
EN

Stack Overflow用户

发布于 2015-10-14 01:27:42

在这个网络/http代码的一部分中,您的答案是:

代码语言:javascript
复制
    // 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() {
        return
    }
    w.finishRequest()

ServeHTTP返回后,请求就完成了。

所以你有几个解决方案:

  • 删除员工模式并在serveHandler中完成工作
  • 在完成serveHandler之前,等待请求被完全处理,如下所示:

(在我的本地测试)

代码语言:javascript
复制
type clientRequest struct {
    r *http.Request
    w http.ResponseWriter
    done chan struct{}
}

func serveHandler(w http.ResponseWriter, r *http.Request) {
    var newRequest = new(clientRequest)
    newRequest.r = r
    newRequest.w = w
    newRequest.done = make(chan struct{})

    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))
    <-newRequest.done // wait for the worker to finish
}

func processRequest(instanceNbr int) {
    fmt.Printf("processRequest started for instance #%d\n", instanceNbr)
    for theRequest := range reqChannel { // receive requests from the channel until it is closed
        fmt.Printf("Got request from reqChannel for URL: %q\n", html.EscapeString(theRequest.r.URL.Path))

        // xxx this isn't working:
        fmt.Fprintf(theRequest.w, "processRequest instance #%d: URL is %q", instanceNbr, html.EscapeString(theRequest.r.URL.Path))
        if f, ok := theRequest.w.(http.Flusher); ok {
            f.Flush()
        }
        theRequest.done <- struct{}{}
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33114991

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档