Golang Gin 实战(十四)| 文件托管、反向代理百度网站、自实现API网关
Golang Gin作为一个优秀的框架,不仅为我们提供了托管文件的能力,还为我们提供了从io.Reader
,这篇文章除了介绍文件托管的使用和原理外,我们还会利用其托管io.Reader
的能力,反向代理www.baidu.com
网站,也就是说,我们在浏览器里访问http://localhost:8080/
就可以看到百度的网站的内容了,就像百度的镜像一样。
通过这篇文章你可以学到(6000多字大章):
- 托管一个静态文件
- 托管一个目录
- 如何实现FTP服务器效果
- 自定义托管内容类型
- 托管一个Reader
- 静态文件托管原理分析
- Gin是如何禁止目录列表的
- 镜像百度网站
- 封装一个直接拿来用的镜像服务代理
- 多域名API服务聚合(API 网关?),解决CROS跨域问题
托管一个静态文件
在项目的开发中,你可能需要这么一个功能:把服务器上的JS文件暴露出来以供访问,比如让网站调用里面的JS函数等。对于这种情形,我们可以使用Gin提供的StaticFile
方法很方便的完成。
func main() {
router := gin.Default()
router.StaticFile("/adobegc.log", "/tmp/adobegc.log")
router.Run(":8080")
}
通过StaticFile
方法,把文件/tmp/adobegc.log
托管在网络上,并且设置访问路径为/adobegc.log
,这样我们通过http://localhost:8080/adobegc.log
就可以访问这个文件,看到它的内容了。
通过这种方式可以托管任何类型的文件,并且我们不用指定Content-Type
,因为会自动识别。
现在我们又有一个需求,想托管很多静态文件,如果使用StaticFile
方法一个个的设置会很繁琐,有没有更简单的方法呢?接着往下看。
托管一个目录
一般情况下,我们会把我们的静态文件放在一个目录中,比如我们使用Gin做网站开发的时候,可以把CSS、JS和Image这些静态资源文件都放在一个目录中,然后使用Static
方法把整个目录托管,这样就可以自由访问这个目录中的所有文件了。
router.Static("/static", "/tmp")
只需要新增这样一行代码就可以实现,非常简单。Static
方法的第一个参数是设置的相对路径,第二个参数是本机目录的绝对路径。
现在我们就可以通过http://localhost:8080/static/adobegc.log
访问上一节里演示的那个adobegc.log
的内容了,和直接访问http://localhost:8080/adobegc.log
效果是一样的。
实现一个FTP服务器
上一节的例子,如果你在浏览器里访问http://localhost:8080/static/
,你会得到404的错误,这是因为Gin做了安全措施,防止第三方恶意罗列获取你服务器上的所有文件。
但是你的需求正好是要搭建一个类似FTP的服务器,就是想把服务器上的文件件共享给其他人使用,比如下载电影等。这时候你就需要一个可以列出目录的功能了,也就是我们访问http://localhost:8080/static/
可以看到/tmp/
目录下的所有文件(包括文件夹),点击文件夹还可以展开看到里面的文件和文件夹,选择合适的文件进行下载,这样就是一个完整的FTP服务器了。
router.StaticFS("/static1", gin.Dir("/tmp", true))
这里我们用到了StaticFS
方法,也是一行代码就可以搞定,为了和上个例子区分,我这里采用/static1
作为相对路径。
这里的关键点在于gin.Dir
函数的第二个参数,true
代表可以列目录的意思。
// if listDirectory == true, then it works the same as http.Dir() otherwise it returns
// a filesystem that prevents http.FileServer() to list the directory files.
func Dir(root string, listDirectory bool) http.FileSystem
现在我们启动访问http://localhost:8080/static1/
就可以看到文件和文件夹列表了,和FTP服务器是类似的。
自定义托管内容类型
以上的示例都是托管一个静态文件或者目录,我们并没有太多的自定义能力,比如设置内容类型,托管一个文件的部分内容等等。
对于这类需求,Gin为我们提供了Data
方法来实现,以第一节中的adobegc.log
为例。
router.GET("/adobegc.log", func(c *gin.Context) {
data, err := ioutil.ReadFile("/tmp/adobegc.log")
if err != nil {
c.AbortWithError(500, err)
} else {
c.Data(200, "text/plain; charset=utf-8", data)
}
})
这个例子实现的效果和上面的是一样的,不一样的是我们通过c.Data
这个方法来实现,这个方法有三个参数:
func (c *Context) Data(code int, contentType string, data []byte)
这就为为我们自定义提供了便利,比如可以指定contentType
和内容data
,这种能力很有用,比如我们可以把我们储存在数据库中的图片二进制数据,作为一张图片显示在网站上。
功能更强大的Reader托管。
除了可以从一个字节数组[]byte
中读取数据显示外,Gin还为我们提供了从一个io.Reader
中获取数据,并且提供了更强大的自定义能力,它就是DataFromReader
方法。
func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string)
从上面的方法签名我们可以看到我们可以自定义的内容:
- 要显示的内容长度
- 内容的类型
- 一个内容源Reader
- 响应的头信息extraHeaders
尤其是自定义的头信息,可以让我们做很多事情,比如缓存等。这个方法的使用比较简单,和上面的Data
方法差不多,这里不再举例,后面我们会通过镜像百度网站这个示例来演示它的使用。
基于源代码分析原理
会使用和知道原理是两码事,面试的时候,面试官也喜欢问具体的源代码实现,这样才能更看出一个人的能力。接下来我们就基于源代码来分析静态文件是如何托管成文件服务的、Gin如果实现安全的防目录列表的;然后会通过Gin的这些能力,镜像一个百度的网站(反向代理),让你访问localhost:8080
就可以访问百度网站;最后会提供一个封装好的类库(直接拿来用),可以非常方便的通过Gin反向代理任意服务,通过它你可以实现聚和多个域名上的API服务,可以解决浏览器跨域的问题。
- css3 过渡和2d变换——回顾
- Microsoft 防跨站点脚本库AntiXSS Library v4.2.1
- Compilify——让你在浏览器中编译.NET代码
- Python进阶-面向对象
- WCF RESTful服务的Google Protocol Buffers超媒体类型
- 使用CoreOs,Docker和Nirmata部署微服务类型的应用
- .NET 4 上的REST 框架
- 结合游戏开发与人工智能研究,游戏大厂 Ubisoft 成立AI研发部门
- Quartz.NET的管理工具
- Python-执行系统命令
- css3 UI 修饰——回顾
- Windows Phone 7实战 第一天 设计启动页面和应用程序图标
- css3响应式布局设计——回顾
- Windows Phone 7 实战第二天 二维码QRcode
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 设计模式(五)-工厂方法模式
- html 的div或其他元素监听 resize事件不生效的解决办法
- 基于docker部署skywalking实现全链路监控
- 数据结构与算法(二)——十大排序算法
- VUE项目使用.env文件配置全局环境变量
- 设计模式学习(六)-抽象工厂模式
- 彻底完美解决安卓苹果手机点击输入框网页页面自动放大缩小
- 第22天:NLP实战(六)——基于PaddleHub的疫情期间网民情绪识别
- Echarts大数据可视化物流航向省份流向迁徙动态图,开发全解+完美参数注释
- Linux 常用操作以及概念
- GCD梳理与总结——封装
- 原生JS在网页上复制的所有文字后面自动加上一段版权声明
- 使用宝塔docker安装为知笔记私有部署
- 第4天:美团点评2020校招测试方向笔试试卷分析
- Element-UI饿了么时间组件控件按月份周日期,开始时间结束时间范围限制参数