一、需求
A(客户端)---------------》B(服务端)--------------》C(文件服务器)
在客户端需要显示图片列表,但是不想C(文件服务器)的地址被暴露出来,所以现在是A(客户端)发送URL到B(服务器),B(服务器)去请求C(文件服务器)的图片返回数据,B(服务器)返回图片到A(客户端)显示
注:B和C部署在不同的服务器
二、方法
1.如果C(文件服务器)是和B(服务端)部署在同一服务器,可以通过os.Open(filename string)(file *File,err error)直接将图片输出;
2.如果C(文件服务器)不是和B(服务端)部署在同一服务器,可以通过获取图片的数据经过base64后转化将数据输出到客户端;
3.如果C(文件服务器)不是和B(服务端)部署在同一服务器,通过B(服务端)获取C(文件服务器)的图片数据,直接将图片返回给客户端(下面实现)
三、实现方法3
1.如何将图片可以直接输出到客户端,可根据os.Open(filename string)(file *File,err error)方法来实现返回http.File接口类型即可;
2.查看golang标准库可知道http.File类型接口的实现(net/http)
type File interface {
io.Closer
io.Reader
Readdir(count int) ([]os.FileInfo, error)
Seek(offset int64, whence int) (int64, error)
Stat() (os.FileInfo, error)
}
3.通过看http.File接口的方法返回值还需要去实现os.FileInfo类型的接口(查看文档os)
type FileInfo interface { Name() string // 文件的名字(不含扩展名) Size() int64 // 普通文件返回值表示其大小;其他文件的返回值含义各系统不同 Mode() FileMode // 文件的模式位 ModTime() time.Time // 文件的修改时间 IsDir() bool // 等价于Mode().IsDir() Sys() interface{} // 底层数据来源(可以返回nil) }
4.只要实现了http.File和os.FileInfo两个接口就可以返回能够输出到客户端的类型,实现以下方法
func Close() (err error)
func Read(p []byte) (n int, err error)
func Readdir(count int) ([]os.FileInfo, error)
func Seek(offset int64, whence int) (int64, error)
func Stat() (os.FileInfo, error)
func Name() string
func Size() int64
func Mode() os.FileMode
func ModTime() time.Time
func IsDir() bool
func Sys() interface{}
四、代码实现
package main import ( "bytes" "fmt" "io/ioutil" "net/http" "os" "path/filepath" "time" ) //实现File和FileInfo接口的类 type ReadImg struct { buf *bytes.Reader fileUrl string fileData []byte } //获取C的图片数据 func ReadImgData(url string) []byte { resp, err := http.Get(url) if err != nil { panic(err) } defer resp.Body.Close() pix, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } return pix } //实现File和FileInfo接口 func (r *ReadImg) Close() (err error) { return nil } func (r *ReadImg) Read(p []byte) (n int, err error) { return r.buf.Read(p) } func (r *ReadImg) Readdir(count int) ([]os.FileInfo, error) { var i os.FileInfo = &ReadImg{buf: bytes.NewReader(r.fileData), fileUrl: r.fileUrl, fileData: r.fileData} return []os.FileInfo{i}, nil } func (r *ReadImg) Seek(offset int64, whence int) (int64, error) { return r.buf.Seek(offset, whence) } func (r *ReadImg) Stat() (os.FileInfo, error) { var i os.FileInfo = &ReadImg{buf: bytes.NewReader(r.fileData), fileUrl: r.fileUrl, fileData: r.fileData} return i, nil } func (r *ReadImg) Name() string { return filepath.Base(r.fileUrl)[:len(filepath.Base(r.fileUrl))-4] } func (r *ReadImg) Size() int64 { return (int64)(len(r.fileData)) } func (r *ReadImg) Mode() os.FileMode { return os.ModeSetuid } func (r *ReadImg) ModTime() time.Time { return time.Now() } func (r *ReadImg) IsDir() bool { return false } func (r *ReadImg) Sys() interface{} { return nil } //处理请求 type HttpDealImg struct{} func (self HttpDealImg) Open(name string) (http.File, error) { img_name := name[1:] fmt.Prin