加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Golang从文件服务器获取图片显示到客户端

发布时间:2020-12-16 09:32:36 所属栏目:大数据 来源:网络整理
导读:一、需求 ? ? ? ?A(客户端)---------------》B(服务端)--------------》C(文件服务器) ? ? ? ?在客户端需要显示图片列表,但是不想C(文件服务器)的地址被暴露出来,所以现在是A(客户端)发送URL到B(服务器),B(服务器)去请求C(文件服务器)的

一、需求

? ? ? ?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,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,error) {
    return r.buf.Seek(offset,whence)
}

func (r *ReadImg) Stat() (os.FileInfo,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.Println(img_name)
    img_url := "http://localhost:8001/images/Test" + name   //C(文件服务器地址)
    img_data := ReadImgData(img_url)  //向服务器气球图片数据
    if len(img_data) == 0 {
        fmt.Println("file access forbidden:",name)
        return nil,os.ErrNotExist
    }
    fmt.Println("get img file:",img_url)
    var f http.File = &ReadImg{buf: bytes.NewReader(img_data),fileUrl: img_name,fileData: img_data}  //标红的可以查看标准库bytes的Reader类型,NewReader(p []byte)可返回*Reader,然后调用和http.File相同的Seek()和Read()方法
    return f,nil
}

func InitHttpImgFileServ() {
    http.Handle("/img/",http.StripPrefix("/img/",http.FileServer(HttpDealImg{})))
}

func main() {
    InitHttpImgFileServ()
    http.ListenAndServe(":8000",nil)
}

六、测试截图

请求地址http://localhost:8000/img/qq.png

后台打印的信息是获取的是http://localhost:8001/images/Test/qq.png,也就是C(文件服务器里图片的真实地址)

?七、结束

? 当文件保存在其他的服务器上,需要在客户端显示图片,但是不想被知道真实的路径的时候就可以通过http.File和os.FileInfo去封装一下就可以实现,可能上面介绍的不清楚,有问题的可以留言一起沟通学习一下,谢谢!

? 如果有更好的实现方法,希望大家可以分享出来一起学习,谢谢

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读