多个 response.WriteHeader 在非常简单的示例中调用?

     2023-02-26     68

关键词:

【中文标题】多个 response.WriteHeader 在非常简单的示例中调用?【英文标题】:multiple response.WriteHeader calls in really simple example? 【发布时间】:2015-03-14 09:27:34 【问题描述】:

我有一个最基本的 net/http 程序,用来学习 Go 中的命名空间:

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() 
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) 
        fmt.Println(r.URL)
        go HandleIndex(w, r)
    )

    fmt.Println("Starting Server...")
    log.Fatal(http.ListenAndServe(":5678", nil))


func HandleIndex(w http.ResponseWriter, r *http.Request) 
    w.WriteHeader(200)
    w.Write([]byte("Hello, World!"))

当我在 Chrome 中运行程序并连接到 localhost:5678 时,我在控制台中得到了这个:

Starting Server...
/
2015/01/15 13:41:29 http: multiple response.WriteHeader calls
/favicon.ico
2015/01/15 13:41:29 http: multiple response.WriteHeader calls

但我不明白这怎么可能。我打印 URL,启动一个新的 goroutine,编写一次标头,并给它一个静态的 Hello, World! 正文,似乎正在发生两件事之一。要么是幕后的东西正在编写另一个标头,要么以某种方式 HandleIndex 为同一个请求调用了两次。我该怎么做才能停止编写多个标题?

编辑:这似乎与go HandleIndex(w, r) 行有关,因为如果我删除go 并使其成为函数调用而不是goroutine,我不会遇到任何问题并且浏览器会获取它的数据.由于它是一个 goroutine,我得到了多个 WriteHeader 错误,并且浏览器没有显示“Hello World”。为什么要让这个 goroutine 破坏它?

【问题讨论】:

【参考方案1】:

看看你注册为传入请求处理程序的匿名函数:

func(w http.ResponseWriter, r *http.Request) 
    fmt.Println(r.URL)
    go HandleIndex(w, r)

它打印 URL(到标准输出)然后在一个新的 goroutine 中调用 HandleIndex() 并继续执行。

如果你有一个处理函数,在第一次调用 Write 之前没有设置响应状态,Go 会自动将响应状态设置为 200(HTTP OK)。如果处理函数没有向响应写入任何内容(并且没有设置响应状态并正常完成),则也将其视为成功处理请求,并将返回响应状态 200。您的匿名函数没有设置它,它甚至没有向响应写入任何内容。所以 Go 会这样做:将响应状态设置为 200 HTTP OK。

请注意,处理每个请求都在其自己的 goroutine 中运行。

所以如果你在一个新的 goroutine 中调用 HandleIndex,你原来的匿名函数将继续:它会结束,所以响应头将被设置 - 同时(同时)你启动的新 goroutine 也将设置响应头 - 因此"multiple response.WriteHeader calls" 错误。

如果你删除"go",你的HandleIndex函数将在你的处理函数返回之前在同一个goroutine中设置响应头,并且“net/http”会知道这一点并且不会尝试设置响应再次标头,因此您遇到的错误不会发生。

【讨论】:

"请注意,处理每个请求都在其自己的 gorouting 中运行。"我希望它能做到这一点,但如果这是真的,我从来没有见过任何说法。 @CoreyOgburn 引用 http.Serve() 的文档:"Serve accepts incoming HTTP connections on the listener l, creating a new service goroutine for each."【参考方案2】:

您已经收到了解决您问题的正确答案,我将提供一些关于一般情况的信息(此类错误经常出现)。

在documentation 中,您看到WriteHeader 发送了一个http 状态代码,并且您不能发送超过1 个状态代码。如果你Write 什么都相当于发送 200 个状态码然后写东西。

因此,如果您多次明确使用w.WriteHeader 或在w.WriteHeader 之前使用w.Write,则会显示您看到的消息。

【讨论】:

【参考方案3】:

来自文档:

// WriteHeader sends an HTTP response header with status code. 
// If WriteHeader is not called explicitly, the first call to Write  
// will trigger an implicit WriteHeader(http.StatusOK).

您的情况是您正在从处理程序启动go HandleIndex。 第一个处理程序完成。标准 WriteHeader 写入 ResponseWriter。然后启动 goroutine HandleIndex,它也尝试写一个 header 和 write。

只需从 HandleIndex 中删除 go 即可。

【讨论】:

【参考方案4】:

根本原因是您多次调用 WriteHeader。来自源代码

func (w *response) WriteHeader(code int) 
    if w.conn.hijacked() 
        w.conn.server.logf("http: response.WriteHeader on hijacked connection")
        return
    
    if w.wroteHeader 
        w.conn.server.logf("http: multiple response.WriteHeader calls")
        return
    
    w.wroteHeader = true
    w.status = code

    if w.calledHeader && w.cw.header == nil 
        w.cw.header = w.handlerHeader.clone()
    

    if cl := w.handlerHeader.get("Content-Length"); cl != "" 
        v, err := strconv.ParseInt(cl, 10, 64)
        if err == nil && v >= 0 
            w.contentLength = v
         else 
            w.conn.server.logf("http: invalid Content-Length of %q", cl)
            w.handlerHeader.Del("Content-Length")
        
    

所以当你写一次时,变量 writeHeader 为真,然后你再次写 header,它不会生效并给出警告“http: multiple respnse.WriteHeader calls”。 实际上函数Write也调用了WriteHeader,所以把函数WriteHeader放在函数Write之后也会导致该错误,而后面的WriteHeader不起作用。

从你的情况来看,go handleindex在另一个线程中运行,原来的已经返回,如果你什么都不做,它会调用WriteHeader设置200。运行handleindex时,它会调用另一个WriteHeader,此时writeHeader为true,那么输出消息“http: multiple response.WriteHeader calls”。

【讨论】:

【参考方案5】:

是的,使用HandleIndex(w, r) 而不是go HandleIndex(w, r) 可以解决您的问题,我想您已经弄清楚了。

原因很简单,当同时处理多个请求时,http server会启动多个goroutine,你的handler函数会在每个goroutine中单独调用,不会阻塞其他的。 您不需要在处理程序中启动自己的 goroutine,除非您实际上需要它,但这将是另一个话题。

【讨论】:

【参考方案6】:

因为现代浏览器会发送一个额外的 /favicon.ico 请求,该请求也在您的 / 请求处理程序中处理。

例如,如果您使用 curl ping 服务器,您将看到只发送一个请求:

 curl localhost:5678

为了确保您可以在 http.HandleFunc 中添加 EndPoint

http.HandleFunc("/Home", func(w http.ResponseWriter, r *http.Request) 

【讨论】:

nodenpmmysql怎么用

...http");varserver=http.createServer(function(request,response)response.writeHeader(200,"Content-Type":"text/html");client.query('SELECT*FROMtags',functionselectCb(err,results, 查看详情

node如何使用mysql

...varserver=http.createServer(function(request,response)  response.writeHeader(200,"Content-Type":"text/html&quo 查看详情

使用相同的语句对象在多个线程中执行多个查询?

】使用相同的语句对象在多个线程中执行多个查询?【英文标题】:usingsamestatementobjecttoexecutemultiplequeriesinmultiplethreads?【发布时间】:2014-08-0707:54:08【问题描述】:重复使用java.sql.Statement对象来在多个线程中同时执行多个查询是... 查看详情

XPath 在多个级别具有多个条件?

】XPath在多个级别具有多个条件?【英文标题】:XPathwithmultipleconditionsatmultiplelevels?【发布时间】:2022-01-0302:15:32【问题描述】:我有一个xml文件,我需要检索节点“DocIDAu​​toNumerator”值,但如果提交的“ActivityTime”包含今天... 查看详情

在多个条件上旋转多个列

】在多个条件上旋转多个列【英文标题】:PivotMultipleColumnsonMultipleCriteria【发布时间】:2016-02-2619:17:04【问题描述】:我是SQL新手,并且在学习过程中不断学习。我正在尝试基于2个列标题来透视表。我当前的文件标题是年份、类... 查看详情

如何在多个数组的索引处保存多个元素?

】如何在多个数组的索引处保存多个元素?【英文标题】:Howtosavemultipleelementsatindexformultiplearrays?【发布时间】:2015-11-1721:38:44【问题描述】:我正在建立这样的数组......varvidRankArray=[String]()varvidIdArray=[String]()varvidTitleArray=[String](... 查看详情

MySQL:在存储过程中选择多个字段到多个变量中

】MySQL:在存储过程中选择多个字段到多个变量中【英文标题】:MySQL:Selectingmultiplefieldsintomultiplevariablesinastoredprocedure【发布时间】:2011-01-2721:01:46【问题描述】:我可以在MySQL的同一个选择查询中将多个列选择到多个变量中吗?... 查看详情

同时在多个元素上添加/删除多个类

】同时在多个元素上添加/删除多个类【英文标题】:Add/Removemultipleclassesonmultipleelementssimultaneously【发布时间】:2014-09-2704:19:51【问题描述】:我想要实现的是使用单个元素,通过onclick,同时在2个独立元素上添加和删除2个类名... 查看详情

r语言使用ggplot2同时可视化dataframe的多个数据列实战:多个数据列可视化在同一个图中多个数据列可视化在多个图中(纵向多个子图)

R语言使用ggplot2同时可视化dataframe的多个数据列实战:多个数据列可视化在同一个图中、多个数据列可视化在多个图中(纵向多个子图)目录 查看详情

在多个项目/模块中使用多个属性文件(通过 PropertyPlaceholderConfigurer)

】在多个项目/模块中使用多个属性文件(通过PropertyPlaceholderConfigurer)【英文标题】:Usingmultiplepropertyfiles(viaPropertyPlaceholderConfigurer)inmultipleprojects/modules【发布时间】:2011-03-2503:27:30【问题描述】:我们目前正在编写一个分为多... 查看详情

java示例代码_在android中对多个线程使用多个按钮

java示例代码_在android中对多个线程使用多个按钮 查看详情

Websockets 在客户端发送多个事件和多个事件处理程序

】Websockets在客户端发送多个事件和多个事件处理程序【英文标题】:Websocketsmultipleeventssentandmultipleeventhandlersonclientside【发布时间】:2020-10-0507:03:56【问题描述】:最近我开始使用WebSockets进行服务器-客户端通信。问题是当我想... 查看详情

强制多个线程在可用时使用多个 CPU

】强制多个线程在可用时使用多个CPU【英文标题】:ForcingmultiplethreadstousemultipleCPUswhentheyareavailable【发布时间】:2010-11-1610:07:55【问题描述】:我正在编写一个使用大量CPU的Java程序,因为它的工作性质。但是,其中很多可以并行... 查看详情

如何在codeigniter中上传多个/多个图像[重复]

】如何在codeigniter中上传多个/多个图像[重复]【英文标题】:HowtoUploadMultiple/manyimageincodeigniter[duplicate]【发布时间】:2018-08-0102:17:53【问题描述】:我的源代码有问题,当输入许多图像和不同的图像/上传文件时,得到的结果是相... 查看详情

在多个条件下合并来自多个数据帧的数据

】在多个条件下合并来自多个数据帧的数据【英文标题】:mergedatafrommultipledataframesonmultipleconditions【发布时间】:2018-05-3005:37:34【问题描述】:我想合并多个数据框,但前提是键匹配并且日期范围在df1中的“InitialAdmit”日期范围... 查看详情

在 Swift 中将多个 UIButton 添加到多个 UIView

】在Swift中将多个UIButton添加到多个UIView【英文标题】:AddingmultipleUIButtontomultipleUIViewinSwift【发布时间】:2017-10-2112:01:12【问题描述】:我在下面编写了代码,以编程方式创建多个UIButton,这些UIButton被放置在不同的UIView上。所有... 查看详情

在 Kubernetes 中拥有多个命名空间和多个集群有啥区别

】在Kubernetes中拥有多个命名空间和多个集群有啥区别【英文标题】:WhatisthedifferencebetweenhavingmultiplenamespaceandmultipleclusterinKubernetes在Kubernetes中拥有多个命名空间和多个集群有什么区别【发布时间】:2020-10-1813:22:21【问题描述】:... 查看详情

在 MySQL 中使用 LEFT JOINing 多个表搜索多个值

】在MySQL中使用LEFTJOINing多个表搜索多个值【英文标题】:searchformultiplevalueswithLEFTJOINingseveraltablesinMySQL【发布时间】:2016-07-1417:03:25【问题描述】:我在尝试使用LEFTJOINing多个表并使用可能的额外参数进行“全部搜索”来搜索MySQL... 查看详情