经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
Golang从文件服务器获取图片显示到客户端
来源:cnblogs  作者:Adver  时间:2018/11/6 16:39:53  对本文有异议

一、需求

       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)

     

  1. type File interface {
  2. io.Closer
  3. io.Reader
  4. Readdir(count int) ([]os.FileInfo, error)
  5. Seek(offset int64, whence int) (int64, error)
  6. Stat() (os.FileInfo, error)
  7. }

   3.通过看http.File接口的方法返回值还需要去实现os.FileInfo类型的接口(查看文档os)

  1. type FileInfo interface {
  2. Name() string // 文件的名字(不含扩展名)
  3. Size() int64 // 普通文件返回值表示其大小;其他文件的返回值含义各系统不同
  4. Mode() FileMode // 文件的模式位
  5. ModTime() time.Time // 文件的修改时间
  6. IsDir() bool // 等价于Mode().IsDir()
  7. Sys() interface{} // 底层数据来源(可以返回nil)
  8. }

  4.只要实现了http.File和os.FileInfo两个接口就可以返回能够输出到客户端的类型,实现以下方法

  1. func Close() (err error)
  2. func Read(p []byte) (n int, err error)
  3. func Readdir(count int) ([]os.FileInfo, error)
  4. func Seek(offset int64, whence int) (int64, error)
  5. func Stat() (os.FileInfo, error)
  6. func Name() string
  7. func Size() int64
  8. func Mode() os.FileMode
  9. func ModTime() time.Time
  10. func IsDir() bool
  11. func Sys() interface{}

四、代码实现

  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "net/http"
  7. "os"
  8. "path/filepath"
  9. "time"
  10. )
  11. //实现File和FileInfo接口的类
  12. type ReadImg struct {
  13. buf *bytes.Reader
  14. fileUrl string
  15. fileData []byte
  16. }
  17. //获取C的图片数据
  18. func ReadImgData(url string) []byte {
  19. resp, err := http.Get(url)
  20. if err != nil {
  21. panic(err)
  22. }
  23. defer resp.Body.Close()
  24. pix, err := ioutil.ReadAll(resp.Body)
  25. if err != nil {
  26. panic(err)
  27. }
  28. return pix
  29. }
  30. //实现File和FileInfo接口
  31. func (r *ReadImg) Close() (err error) {
  32. return nil
  33. }
  34. func (r *ReadImg) Read(p []byte) (n int, err error) {
  35. return r.buf.Read(p)
  36. }
  37. func (r *ReadImg) Readdir(count int) ([]os.FileInfo, error) {
  38. var i os.FileInfo = &ReadImg{buf: bytes.NewReader(r.fileData), fileUrl: r.fileUrl, fileData: r.fileData}
  39. return []os.FileInfo{i}, nil
  40. }
  41. func (r *ReadImg) Seek(offset int64, whence int) (int64, error) {
  42. return r.buf.Seek(offset, whence)
  43. }
  44. func (r *ReadImg) Stat() (os.FileInfo, error) {
  45. var i os.FileInfo = &ReadImg{buf: bytes.NewReader(r.fileData), fileUrl: r.fileUrl, fileData: r.fileData}
  46. return i, nil
  47. }
  48. func (r *ReadImg) Name() string {
  49. return filepath.Base(r.fileUrl)[:len(filepath.Base(r.fileUrl))-4]
  50. }
  51. func (r *ReadImg) Size() int64 {
  52. return (int64)(len(r.fileData))
  53. }
  54. func (r *ReadImg) Mode() os.FileMode {
  55. return os.ModeSetuid
  56. }
  57. func (r *ReadImg) ModTime() time.Time {
  58. return time.Now()
  59. }
  60. func (r *ReadImg) IsDir() bool {
  61. return false
  62. }
  63. func (r *ReadImg) Sys() interface{} {
  64. return nil
  65. }
  66. //处理请求
  67. type HttpDealImg struct{}
  68. func (self HttpDealImg) Open(name string) (http.File, error) {
  69. img_name := name[1:]
  70. fmt.Println(img_name)
  71. img_url := "http://localhost:8001/images/Test" + name //C(文件服务器地址)
  72. img_data := ReadImgData(img_url) //向服务器气球图片数据
  73. if len(img_data) == 0 {
  74. fmt.Println("file access forbidden:", name)
  75. return nil, os.ErrNotExist
  76. }
  77. fmt.Println("get img file:", img_url)
  78. 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()方法
  79. return f, nil
  80. }
  81. func InitHttpImgFileServ() {
  82. http.Handle("/img/", http.StripPrefix("/img/", http.FileServer(HttpDealImg{})))
  83. }
  84. func main() {
  85. InitHttpImgFileServ()
  86. http.ListenAndServe(":8000", nil)
  87. }

六、测试截图

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

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

 七、结束

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

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

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号