英文:
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 </body>
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("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()))
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("my/path")
content, err := dir.Open("my_file") // check error
var r io.ReadSeeker // for http.ServeContent needs
if !strings.HasSuffix("some/web/uri", ".html") {
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 := "<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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论