gpt4 book ai didi

string - ResponseWriter.Write 和 io.WriteString 有什么区别?

转载 作者:行者123 更新时间:2023-12-01 16:46:03 29 4
gpt4 key购买 nike

我见过三种将内容写入 HTTP 响应的方法:

func Handler(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "blabla.\n")
}

和:
func Handler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("blabla\n"))
}

还有:
fmt.Fprintf(w, "blabla")

它们之间有什么区别?首选使用哪一种?

最佳答案

io.Writer
输出流代表一个目标,您可以向其写入字节序列。在 Go 中,这是由一般 io.Writer 捕获的界面:

type Writer interface {
Write(p []byte) (n int, err error)
}

有此单的一切 Write()方法可以用作输出,例如磁盘上的文件 ( os.File )、网络连接 ( net.Conn ) 或内存缓冲区 ( bytes.Buffer )。

http.ResponseWriter 用于配置HTTP响应并将数据发送到客户端的也是这样的 io.Writer ,您要发送的数据(响应正文)是通过调用(不一定只是一次) ResponseWriter.Write() 来组装的(这是为了实现一般 io.Writer )。这是您对 http.ResponseWriter 实现的唯一保证。接口(interface)(关于发送正文)。
WriteString()
现在转到 WriteString() .通常我们想将文本数据写入 io.Writer .是的,我们可以简单地通过转换 string 来做到这一点。到 []byte ,例如
w.Write([]byte("Hello"))

它按预期工作。然而,这是一个非常频繁的操作,因此 io.StringWriter 捕获了一个“普遍”接受的方法。接口(interface)(自 Go 1.12 起可用,在此之前未导出):
type StringWriter interface {
WriteString(s string) (n int, err error)
}

此方法提供了编写 string 的可能性。值而不是 []byte .所以如果某些东西(也实现了 io.Writer )实现了这个方法,你可以简单地传递 string没有 []byte 的值转换。这似乎是代码中的一个小简化,但不仅如此。转换 string[]byte必须复制 string内容(因为 string 值在 Go 中是不可变的,请在此处阅读更多相关信息: golang: []byte(string) vs []byte(*string) ),因此如果 string 有一些开销会变得明显是“更大”和/或您必须多次这样做。

取决于 io.Writer 的性质和实现细节,或许可以写出 string的内容无需将其转换为 []byte从而避免上述开销。

例如,如果 io.Writer是写入内存缓冲区的东西( bytes.Buffer 就是这样的一个例子),它可以利用内置的 copy() 功能:

The copy built-in function copies elements from a source slice into a destination slice. (As a special case, it also will copy bytes from a string to a slice of bytes.)


copy()可用于复制 string 的内容(字节)成 []byte不转换 string[]byte ,例如:
buf := make([]byte, 100)
copy(buf, "Hello")

现在有一个“实用程序”功能 io.WriteString() 写一个 stringio.Writer .但是它通过首先检查(的动态类型)是否通过 io.Writer 来做到这一点。有一个 WriteString()方法,如果是,则将使用该方法(其实现可能更有效)。如果通过 io.Writer没有这样的方法,那么一般的转换为字节 slice 并写入该方法将用作“后备”。

你可能认为这个 WriteString()只会在内存缓冲区的情况下占上风,但事实并非如此。 Web 请求的响应也经常被缓冲(使用内存缓冲区),因此在 http.ResponseWriter 的情况下它可能会提高性能也。如果你看看 http.ResponseWriter 的实现: 这是未导出的类型 http.response ( server.go 当前第 308 行)确实实现了 WriteString() (当前第 1212 行)所以它确实意味着改进。

总而言之,无论何时写 string值,推荐使用 io.WriteString()因为它可能更有效(更快)。
fmt.Fprintf()
您应该将其视为一种方便且简单的方法,可以为要写入的数据添加更多格式,以换取性能稍差。

所以使用 fmt.Fprintf() 如果你想格式化 string以简单的方式创建,例如:
name := "Bob"
age := 23
fmt.Fprintf(w, "Hi, my name is %s and I'm %d years old.", name, age)

这将导致以下 string写成:
Hi, my name is Bob and I'm 23 years old.

你一定不能忘记的一件事: fmt.Fprintf()需要一个格式字符串,因此它将被预处理而不是按原样写入输出。举个简单的例子:
fmt.Fprintf(w, "100 %%")

您会期望 "100 %%"将被写入输出(有 2 个 % 个字符),但只有一个会被发送,如格式字符串 %是一个特殊字符和 %%只会产生一个 %在输出中。

如果你只是想写一个 string使用 fmt打包,使用 fmt.Fprint() 不需要格式 string :
fmt.Fprint(w, "Hello")

使用 fmt 的另一个好处包是你也可以写其他类型的值,而不仅仅是 string s,例如
fmt.Fprint(w, 23, time.Now())

(当然,如何将任何值转换为 string 以及最终转换为一系列字节的规则在 fmt 包的文档中有明确定义。)

对于“简单”格式的输出 fmt包可能没问题。对于复杂的输出文档,请考虑使用 text/template (用于一般文本)和 html/template (只要输出是 HTML)。

传递/移交 http.ResponseWriter
为了完整起见,我们应该提到,您想要作为 Web 响应发送的内容通常是由支持“流式传输”结果的“某物”生成的。一个例子可能是一个 JSON 响应,它是从结构或映射生成的。

在这种情况下,传递/移交您的 http.ResponseWriter 通常更有效。这是一个 io.Writer如果它支持将结果写入 io.Writer即时。

一个很好的例子是生成 JSON 响应。当然,您可以使用 json.Marshal() 将对象编码为 JSON。 ,它返回一个字节 slice ,您可以通过调用 ResponseWriter.Write() 简单地发送它。 .

但是,让 json更有效率包知道你有一个 io.Writer ,最终你想把结果发送给那个。这样就没有必要首先在缓冲区中生成 JSON 文本,您只需将其写入响应然后丢弃。您可以新建一个 json.Encoder 调用 json.NewEncoder() 您可以通过您的 http.ResponseWriter作为 io.Writer ,并调用 Encoder.Encode() 之后将直接将 JSON 结果写入您的响应编写器。

这里的一个缺点是,如果生成 JSON 响应失败,您可能会收到部分发送/提交的响应,而您无法收回。如果这对您来说是个问题,除了在缓冲区中生成响应之外,您实际上别无选择,如果编码(marshal)成功,那么您可以立即编写完整的响应。

关于string - ResponseWriter.Write 和 io.WriteString 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37863374/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com