在代理服务器中实现文件下载并保存到本地,可以通过修改ReverseProxy的Director函数或使用ModifyResponse回调来实现。以下是修改后的代码示例:
func Download(w http.ResponseWriter, r *http.Request) {
golog.Info("downloading.....")
uid := xmux.Var[r.URL.Path]["uid"]
filename := xmux.Var[r.URL.Path]["name"]
es := NewResp()
if v := filelru.FileLru.Get(uid+filename); v != nil {
golog.Info("from cache")
w.Write(v.([]byte))
return
}
var downdata []byte
var err error
if goconfig.ReadBool("proxy", true) {
proxyUrl, _ := url.Parse("http://192.168.1.52")
rp := httputil.NewSingleHostReverseProxy(proxyUrl)
// 保存响应数据到本地
rp.ModifyResponse = func(resp *http.Response) error {
if resp.StatusCode == http.StatusOK {
// 读取响应体
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
// 保存到本地文件
localPath := filepath.Join(goconfig.ReadString("storedir"), uid, filename)
os.MkdirAll(filepath.Dir(localPath), 0755)
err = os.WriteFile(localPath, bodyBytes, 0644)
if err != nil {
return err
}
// 保存到内存缓存
filelru.FileLru.Add(uid+filename, bodyBytes)
downdata = bodyBytes
// 重置响应体供后续使用
resp.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
}
return nil
}
rp.ServeHTTP(w, r)
} else {
downdata, err = ioutil.ReadFile(filepath.Join(goconfig.ReadString("storedir"), uid, filename))
if err != nil {
golog.Error(err.Error())
w.Write(es.ErrorE(err))
return
}
filelru.FileLru.Add(uid+filename, downdata)
w.Write(downdata)
}
}
或者使用更简洁的方式,在代理请求前直接下载文件:
func Download(w http.ResponseWriter, r *http.Request) {
golog.Info("downloading.....")
uid := xmux.Var[r.URL.Path]["uid"]
filename := xmux.Var[r.URL.Path]["name"]
es := NewResp()
if v := filelru.FileLru.Get(uid+filename); v != nil {
golog.Info("from cache")
w.Write(v.([]byte))
return
}
var downdata []byte
var err error
if goconfig.ReadBool("proxy", true) {
// 直接下载文件
client := &http.Client{}
req, _ := http.NewRequest("GET", "http://192.168.1.52"+r.URL.Path, nil)
resp, err := client.Do(req)
if err != nil {
golog.Error(err.Error())
w.Write(es.ErrorE(err))
return
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
// 读取文件数据
downdata, err = io.ReadAll(resp.Body)
if err != nil {
golog.Error(err.Error())
w.Write(es.ErrorE(err))
return
}
// 保存到本地
localPath := filepath.Join(goconfig.ReadString("storedir"), uid, filename)
os.MkdirAll(filepath.Dir(localPath), 0755)
err = os.WriteFile(localPath, downdata, 0644)
if err != nil {
golog.Error(err.Error())
w.Write(es.ErrorE(err))
return
}
// 缓存并返回
filelru.FileLru.Add(uid+filename, downdata)
w.Write(downdata)
return
}
} else {
downdata, err = ioutil.ReadFile(filepath.Join(goconfig.ReadString("storedir"), uid, filename))
if err != nil {
golog.Error(err.Error())
w.Write(es.ErrorE(err))
return
}
filelru.FileLru.Add(uid+filename, downdata)
w.Write(downdata)
}
}
第一个方案使用ModifyResponse回调在代理过程中保存文件,第二个方案直接下载文件后再代理返回。两个方案都能实现将远程文件保存到本地服务器的需求。