我正在用golang构建一个简单的测试API,用于上传和下载图像文件(PNG、JPEG、JPG):
/pic发布上传图像并将其保存到文件夹;/pic GET用于将图像下载到客户端。
我已经成功地构建了/pic帖子,并成功地将图像上传到服务器的文件中。我可以打开存储文件夹中的文件。(在windows localhost服务器和ubuntu服务器中)
但是,当我构建用于下载图片的/pic GET时,我可以将该文件下载到客户端(我的计算机),但是下载的文件以某种方式损坏了,因为当我尝试用不同的图像查看器(如图片库或Photoshop )打开它时,它说“看起来我们不支持这种文件格式”。因此,下载似乎并不成功。
邮递员结果:

图库中的文件打开:

对于为什么会发生这种情况,我应该如何解决它,有什么想法吗?
下载图片的golang代码如下(省略错误处理):
func PicDownload(w http.ResponseWriter, r *http.Request){
request := make(map[string]string)
reqBody, _ := ioutil.ReadAll(r.Body)
err = json.Unmarshal(reqBody, &request)
// Error handling
file, err := os.OpenFile("./resources/pic/" + request["filename"], os.O_RDONLY, 0666)
// Error handling
buffer := make([]byte, 512)
_, err = file.Read(buffer)
// Error handling
contentType := http.DetectContentType(buffer)
fileStat, _ := file.Stat()
// Set header
w.Header().Set("Content-Disposition", "attachment; filename=" + request["filename"])
w.Header().Set("Content-Type", contentType)
w.Header().Set("Content-Length", strconv.FormatInt(fileStat.Size(), 10))
// Copying the file content to response body
io.Copy(w, file)
return
}发布于 2020-02-04 11:26:01
当您从文件中读取前512字节以确定内容类型时,基础文件流指针向前移动512字节。稍后调用io.Copy时,从该位置继续读取。
有两种方法可以纠正这种情况。
首先是在调用file.Seek(0, io.SeekStart)之前调用io.Copy()。这将使指针返回到文件的开始。此解决方案需要最少的代码,但意味着从文件中读取相同的512字节两次,这会造成一些开销。
第二个解决方案是使用buffer := make([]byte, fileStat.Size()创建一个包含整个文件的缓冲区,并为http.DetectContentType()调用使用该缓冲区,并编写输出(使用w.Write(buffer)而不是使用io.Copy() )。这种方法可能会同时将整个文件加载到内存中,这对于非常大的文件来说并不理想(io.Copy使用32 at块而不是加载整个文件)。
注意:正如Peter在评论中提到的,您必须确保用户不能以文件名的形式发布../../或其他内容来遍历您的文件系统。
https://stackoverflow.com/questions/60054675
复制相似问题