我有一个将在每个HTTP GET请求上调用的函数。该函数读取文件,对该文件的内容执行一些操作,并返回这些内容的字节片。然后将那段字节写为HTTP响应编写器的响应主体。
我是否需要为此函数中的任何步骤使用互斥锁,以防止在尝试读取同一文件的多个HTTP请求时锁定?如果是这样,一个简单的RWMutex锁定文件的读取是否足够,因为我实际上并没有写入它但是正在创建其内容的副本?
这是功能:
// prepareIndex will grab index.html and add a nonce to the script tags for the CSP header compliance.
func prepareIndex(nonce string) []byte {
// Load index.html.
file, err := os.Open("./client/dist/index.html")
if err != nil {
log.Fatal(err)
}
// Convert to goquery document.
doc, err := goquery.NewDocumentFromReader(file)
if err != nil {
fmt.Println(err)
}
// Find all script tags and set nonce.
doc.Find("body > script").SetAttr("nonce", nonce)
// Grab the HTML string.
html, err := doc.Html()
if err != nil {
fmt.Println(err)
}
return []byte(html)
}
我还想过在main启动时只加载一次文件,但是我遇到了一个问题,只有第一个请求才能看到数据而后续的请求什么都没看到。我正在阅读文件的方式可能是一个错误。但我实际上更喜欢我当前的方法,因为如果index.html
有任何更改,我希望它们能够立即持久保存给用户而无需重新启动可执行文件。
答案 0 :(得分:2)
使用RWMutex
不会保护您免受其他程序修改的文件的侵害。这里最好的选择是在启动时将文件加载到[]byte
,并在使用"bytes".Buffer
时实例化goquery.NewDocumentFromReader
。为了将更改传播给用户,您可以使用fsnotify [1]检测文件的更改,并在必要时更新缓存的文件([]byte
)(您需要RWMutex
那个操作)。
例如:
type CachedFile struct {
sync.RWMutex
FileName string
Content []byte
watcher *fsnotify.Watcher
}
func (c *CachedFile) Buffer() *bytes.Buffer {
c.RLock()
defer c.RUnlock()
return bytes.NewBuffer(c.Content)
}
func (c *CachedFile) Load() error {
c.Lock()
content, err := ioutil.ReadAll(c.FileName)
if err != nil {
c.Unlock()
return err
}
c.Content = content
c.Unlock()
}
func (c *CachedFile) Watch() error {
var err error
c.watcher, err = fsnotify.NewWatcher()
if err != nil {
return err
}
go func() {
for ev := range c.watcher.Events {
if ev.Op != fsnotify.Write {
continue
}
err := c.Load()
if err != nil {
log.Printf("loading %q: %s", c.FileName, err)
}
}
}()
err = c.watcher.Add(c.FileName)
if err != nil {
c.watcher.Close()
return err
}
return nil
}
func (c *CachedFile) Close() error {
return c.watcher.Close()
}
答案 1 :(得分:1)
如果要修改文件,则需要互斥锁。 RWMutex
应该可以正常工作。看起来你只是在阅读它,在这种情况下你不应该看到任何锁定行为或腐败。
第二次从同一个文件句柄中读取时没有获得任何数据的原因是,当您第二次从它开始读取时,您已经在文件的末尾。如果您想再次阅读内容,则需要seek返回偏移0
。