提问人:Yann Bizeul 提问时间:7/5/2023 最后编辑:Yann Bizeul 更新时间:7/5/2023 访问量:80
写作 resp.本地文件的正文有时不完整
Writing resp.Body to a local file sometimes is incomplete
问:
我正在编写一个程序,该程序对某个端点进行大规模的REST调用,然后将结果按原样缓存在本地文件中,并返回一个文件指针供调用者使用。
在99%的情况下,我的代码工作正常,但我随机得到一个不包含请求整个正文的缓存文件。
代码如下所示,调用方仅调用如下:readFromCache()
file, err := CacheProxy{}.readFromCache(url, path.Join("CACHE", a.Hostname, a.ID, s))
func (c CacheProxy) readFromCache(url string, p string) (io.ReadCloser, error) {
c.makeDirectory(p)
file, err := os.Open(p)
if err != nil {
// Can't open the file if it doesn't exists, readFromURL then
return c.readFromURL(url, p)
}
return file, nil
}
func (c CacheProxy) readFromURL(url string, p string) (io.ReadCloser, error) {
client := http.Client{}
resp, err := client.Get(url)
if err != nil {
log.Errorf("Cant read from URL : %s", err)
return nil, err
}
defer resp.Body.Close()
out, err := os.Create(p)
if err != nil {
log.Errorf("Unable to open file : %s", err)
return nil, err
}
writer := bufio.NewWriter(out)
_, err = io.Copy(writer, resp.Body)
if err != nil {
log.Errorf("Unable to copy file : %s", err)
return nil, err
}
writer.Flush()
_, err = out.Seek(0, 0)
if err != nil {
log.Errorf("Unable seek to beginning : %s", err)
return nil, err
}
return out, nil
}
我也试图添加但没有成功out.Sync()
如果我绕过缓存并直接返回,它似乎不会引起任何问题。resp.Body
readFromURL()
我使用的原因是为了提高内存效率。io.Copy()
请注意,我返回一个,调用它是调用它的责任。io.ReadCloser
Close()
我还应该补充一点,这个函数是从不同的线程调用的,但没有调用会指向同一个文件,所以我认为我不会在同一位置写两次并在写文件时覆盖文件。
将结果写入文件的部分似乎相对简单,我希望了解为什么在任何时候输出都会被截断。
我想我捕捉并记录了每一个重要的东西。如果远程服务器意外关闭了流,我会假设返回错误?error
io.Copy()
但在这种情况下,即使直接返回(绕过缓存),我也会有异常,但事实并非如此resp.Body
[更新 1]
以下代码可以正常工作:
func (c CacheProxy) readFromURL(url string, p string) (io.ReadCloser, error) {
resp, err := http.Get(url)
if err != nil {
log.Errorf("Cant read from URL : %s", err)
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("ResultCode != 200 (%d), aborting", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Errorf("Error while reading body : %s", err)
return nil, err
}
os.WriteFile(p, body, 0600)
out, err := os.Open(p)
if err != nil {
log.Errorf("Cannot reopen file : %s", err)
return nil, err
}
return out, nil
}
这让我想知道我做错了什么,而且,我不喜欢目前我必须在内存中加载所有内容才能编写它。io.Copy()
bufio.Writer
[更新2]
我试图使用而不是,同样的问题发生了:file.ReadFrom()
io.Copy()
func (c CacheProxy) readFromURL(url string, p string) (io.ReadCloser, error) {
resp, err := http.Get(url)
if err != nil {
log.Errorf("Cant read from URL : %s", err)
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("ResultCode != 200 (%d), aborting", resp.StatusCode)
}
out, err := os.Create(p)
if err != nil {
log.Errorf("Unable to open file : %s", err)
return nil, err
}
out.ReadFrom(resp.Body)
if err != nil {
log.Errorf("Unable to read stream : %s", err)
return nil, err
}
err = out.Close()
if err != nil {
log.Errorf("Error while closing file : %s", err)
return nil, err
}
out, err = os.Open(p)
if err != nil {
log.Errorf("Cannot reopen file : %s", err)
return nil, err
}
return out, nil
}
[更新3]
有趣的是,有时文件没有被截断,但缺少开头,结尾很好,这似乎非常奇怪。我想我的线程做错了什么,但我被告知 http。客户端是完全线程安全的,我应该能够始终如一地从不同线程中的不同请求中读取不同的正文。
答: 暂无答案
评论
out
Close()
out
Copy()
io.Copy
nil
writer.Flush()
"Unable to copy to file :"
io.Copy()