在飞行中修改ServeContent文件

huangapple go评论79阅读模式
英文:

Modify ServeContent file on the fly

问题

我正在编写一个简单的Web服务器来提供静态文件。任何被提供的HTML文件都需要在其关闭的</body>标签之前进行修改。

我使用下面的代码实现了这个功能,并且它可以正常工作,但是是否有更高效的方法呢?我是Go的初学者,所以这段代码需要具有超高的性能。

// 省略了错误处理等部分

dir := http.Dir("my/path")

content, _ := dir.Open("my_file")

var bodyBuf strings.Builder
var contentBuf *bytes.Buffer

io.Copy(&bodyBuf, content)
defer content.Close()

if strings.HasSuffix("some/web/uri", ".html") {
    new_html_content := "<whatever></body>"
    bodyRpld := strings.Replace(bodyBuf.String(), "</body>", new_html_content, 1)
    contentBuf = bytes.NewBuffer([]byte(bodyRpld))
} else {
    contentBuf = bytes.NewBuffer([]byte(bodyBuf.String()))
}

d, _ := content.Stat()

http.ServeContent(w, r, "my/path", d.ModTime(), bytes.NewReader(contentBuf.Bytes()))

谢谢!

英文:

I'm writing a simple web server to serve static files. Any HTML file being served needs to be modified "on the go" to include some HTML just before its closing &lt;/body&gt; tag.

I achieved it with the below code and it works, however is there perhaps a more efficient way of doing it? I'm beginner in Go and this code needs to be super performant.

// error handling etc omitted for brevity

dir := http.Dir(&quot;my/path&quot;)

content, _ := dir.Open(&quot;my_file&quot;)

var bodyBuf strings.Builder
var contentBuf *bytes.Buffer

io.Copy(&amp;bodyBuf, content)
defer content.Close()

if strings.HasSuffix(&quot;some/web/uri&quot;, &quot;.html&quot;) {
    new_html_content := &quot;&lt;whatever&gt;&lt;/body&gt;&quot;
    bodyRpld := strings.Replace(bodyBuf.String(), &quot;&lt;/body&gt;&quot;, new_html_content, 1)
    contentBuf = bytes.NewBuffer([]byte(bodyRpld))
} else {
    contentBuf = bytes.NewBuffer([]byte(bodyBuf.String()))
}

d, _ := content.Stat()

http.ServeContent(w, r, &quot;my/path&quot;, d.ModTime(), bytes.NewReader(contentBuf.Bytes()))

Thanks!

答案1

得分: 1

为了避免为不符合文件匹配模式*.html的文件创建大型缓冲区,我建议使用io.Reader机制来传递你想要保持原样的文件。这样可以避免将潜在的大型资源(例如100MB的非HTML视频文件)加载到内存中。

对于符合你的html检查的文件,你的字符串替换可能是可以的,因为.html文件通常很小。

所以可以尝试像这样的代码:

dir := http.Dir("my/path")
content, err := dir.Open("my_file") // 检查错误

var r io.ReadSeeker // 用于http.ServeContent

if !strings.HasSuffix("some/web/uri", ".html") {
    r = content // 传递文件内容(避免内存分配)
} else {
    // 类似于你之前的代码
    b := new(bytes.Buffer)
    n, err := b.ReadFrom(content) // 检查错误
    defer content.Close()

    new_html_content := "<whatever></body>"
    newContent := strings.Replace(b.String(), "</body>", new_html_content, 1)

    r = bytes.NewReader([]byte(newContent))
}

d, _ := content.Stat()

http.ServeContent(w, r, "my/path", d.ModTime(), r)

请注意,这只是一个示例代码,你需要根据你的实际需求进行适当的修改。

英文:

To avoid creating large buffers for files that do no match your file-match pattern *.html, I would suggest using an io.Reader mechanism to pass-through files that you want to serve untouched. This avoids loading into memory potentially large assets (e.g. 100MB non-html video files).

For files that do match your html check - your string-replace is probably fine as .html are typically small in size.

So try something like this:

dir := http.Dir(&quot;my/path&quot;)
content, err := dir.Open(&quot;my_file&quot;) // check error

var r io.ReadSeeker // for http.ServeContent needs

if !strings.HasSuffix(&quot;some/web/uri&quot;, &quot;.html&quot;) {

    r = content // pass-through file content (avoid memory allocs)

} else {

    // similar to what you had before
    b := new(bytes.Buffer)
    n, err := b.ReadFrom(content) // check err
    defer content.Close()

    new_html_content := &quot;&lt;whatever&gt;&lt;/body&gt;&quot;
    newContent := strings.Replace(b.String(),
        &quot;&lt;/body&gt;&quot;, new_html_content, 1)

    r = bytes.NewReader([]byte(newContent))
}

d, _ := content.Stat()

http.ServeContent(w, r, &quot;my/path&quot;, d.ModTime(), r)

huangapple
  • 本文由 发表于 2021年8月16日 18:47:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/68801514.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定