欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-10-15 16:39:24
一、需求 A(客户端) 》B(服务端) 》C(文件服务器) 在客户端需要显示图片列表,但是不想C(文件服务器)的地址被暴露出来,所以现在是A(客户端)发送URL到B(服务器),B(服务器)去请求C(文件服务器)的图片返回数据,B(服务器)返回图片到A(客户端)显示 注: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, 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.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)
}

六、测试截图

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

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

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

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

 七、结束

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

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