Go语言中间件框架 Negroni 的静态文件处理源码分析

栏目: Go · 发布时间: 6年前

内容简介:Negroni是一个非常棒的中间件,尤其是其中间件调用链优雅的设计,以及对GO HTTP 原生处理器的兼容。我以前写过两篇文章,对Negroni进行了专门的分析,没有看过的朋友可以在看下。Go语言经典库使用分析(五)| Negroni 中间件(一)Go语言经典库使用分析(六)| Negroni 中间件(二)

Negroni是一个非常棒的中间件,尤其是其中间件调用链优雅的设计,以及对GO HTTP 原生处理器的兼容。我以前写过两篇文章,对Negroni进行了专门的分析,没有看过的朋友可以在看下。

Go语言经典库使用分析(五)| Negroni 中间件(一) http://www.flysnow.org/2017/08/20/go-classic-libs-negroni-one.html

Go语言经典库使用分析(六)| Negroni 中间件(二) http://www.flysnow.org/2017/09/02/go-classic-libs-negroni-two.html

Negroni Static中间件

Negroni设计的时候,内置了3个中间件,它们分别是Logger、Recovery和Static,用于日志处理,故障恢复以及静态文件处理,今天来分析下静态文件处理的源码实现。

Negroni的静态文件处理中间件,主要是为了把我们电脑(服务器)上的文件托管到Web服务上,可以通过HTTP的方式访问查看对应的电脑上的文件。如果请求的文件不存在,那么请求将会转给下一个中间件;如果文件存在,那么就会显示静态文件的内容,请求到此终止。

使用Negroni实现静态处理非常简单,我们看一个示例。

package main

import (
	"github.com/urfave/negroni"
	"net/http"
)

func main(){
	n := negroni.New()
	n.Use(negroni.NewLogger())
	n.Use(negroni.NewStatic(http.Dir("/tmp")))
	n.Run(":8080")
}

示例中,把 /tmp 目录下的文件,托管在了Web服务器上,可以通过HTTP的方式访问到。假如 /tmp 下有一个 1.txt 文件,那么我们打开浏览器,输入地址 http://127.0.0.1:8080/1.txt 即可访问对应的 1.txt 文件的内容。

示例中,我添加了一个 n.Use(negroni.NewLogger()) 中间件,用于打印访问日志,比如请求的URL等。

从示例代码中,可以看到,Negroni主要通过 negroni.NewStatic 函数,生成一个静态文件处理的中间件。

// NewStatic returns a new instance of Static
func NewStatic(directory http.FileSystem) *Static {
	return &Static{
		Dir:       directory,
		Prefix:    "",
		IndexFile: "index.html",
	}
}

该函数接受一个 http.FileSystem 类型的参数,用于指定要处理的目录。从函数的源代码可以看出,返回的其实是一个 *Static ,这个 Static 结构体有三个字段。

Negroni Static 结构体分析

type Static struct {
	// 静态服务要处理目录
	Dir http.FileSystem
	// 给这些静态文件添加的URL前缀,主要用于对处理的静态文件分类
	Prefix string
	// 索引文件,访问Dir目录的时候,显示这个索引文件的内容
	IndexFile string
}

第一个字段我们已经在示例中演示了,下面看看另外两个字段的用法,我通过示例说明,更容易理解。

Negroni Static Prefix 分析

现在我要托管 /tmp 目录下的文件,但是我又想通过 http://hostname/tmp/1.txt 这样的方式进行归类,让访问的人知道,这些文件是在 tmp/ 下的,这就可以用到 Prefix 字段了。我们把原来的示例修改下看看。

func main(){
	n := negroni.New()
	n.Use(negroni.NewLogger())
	n.Use(&negroni.Static{
		Dir:       http.Dir("/tmp"),
		Prefix:    "/tmp",
		IndexFile: "index.html",
	})


	n.Run(":8080")
}

我们不再使用 NewStatic 方法,而是直接通过 &negroni.Static{} 构建一个静态文件处理的中间件,在构建的时候,指定 Prefix 的值为 /tmp ,现在我们再访问 /tmp 下的 1.txt 文件,就只能通过 http://127.0.0.1:8080/tmp/1.txt ,而不是原来的 http://127.0.0.1:8080/1.txt ,这样我们通过给URL加前缀,达到文件分类的目的,其实就是增加一个URL path。

本文为原创文章,转载注明出处&&,欢迎扫码关注公众号 flysnow_org 或者网站 http://www.flysnow.org/ ,&&第一时间看后续精彩文章。觉得好的话,&&顺手分享到朋友圈吧,感谢支持。

以上这些是如何实现的呢?我们看下静态文件处理的源代码,结合分析。

file := r.URL.Path
	// if we have a prefix, filter requests by stripping the prefix
	if s.Prefix != "" {
		if !strings.HasPrefix(file, s.Prefix) {
			next(rw, r)
			return
		}
		file = file[len(s.Prefix):]
		if file != "" && file[0] != '/' {
			next(rw, r)
			return
		}
	}
	f, err := s.Dir.Open(file)

以上这段代码,是通过URL路径,查找对应的静态文件的核心代码。从源代码中可以看到,对 Prefix 不为空的情况进行了特殊处理,如果 Prefix 不为空,那么我们就要从URL Path中去掉这个 Prefix ,因为 Prefix 是我们自己强加入的,不属于文件路径中的部分,所以要剥离掉,这样才可以得到要处理文件的真实路径,也就是源代码中的 file 变量,最后通过 s.Dir.Open(file) 打开文件,得到其内容显示即可。

Negroni Static IndexFile 分析

最后一个字段是 IndexFile ,用于指定索引文件。对于我们使用过Apache、Nginx的都比较熟悉,我们指定了 index.html 作为索引文件后,那么我们再访问 http://127.0.0.1:8080/tmp/ 这个目录,显示的其实是 index.html 文件的内容,因为我们访问的其实是 http://127.0.0.1:8080/tmp/index.html ,这就是 IndexFile 的作用。

Negroni的静态处理器中间件源代码中,对于 IndexFile 也非常简洁,容易理解。

// try to serve index file
	if fi.IsDir() {
		file = path.Join(file, s.IndexFile)
		f, err = s.Dir.Open(file)
	}
	//省略了无关代码

这个源代码处理很简单,如果是一个目录的话,就把目录和 IndexFile 拼接成一个新的文件路径,进行二次打开。

如何在请求页面上显示文件内容

在一系列的打开、判断中,如果最后可以找到正确的文件,拿到内容,那么就可以把内容展示到浏览器的页面上了。

http.ServeContent(rw, r, file, fi.ModTime(), f)

非常简洁的一段代码,即达到了我们的目的,该函数可以把 ReadSeeker 中的内容,显示到请求的页面上。

func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time, content io.ReadSeeker) {
	sizeFunc := func() (int64, error) {
		size, err := content.Seek(0, io.SeekEnd)
		if err != nil {
			return 0, errSeeker
		}
		_, err = content.Seek(0, io.SeekStart)
		if err != nil {
			return 0, errSeeker
		}
		return size, nil
	}
	serveContent(w, req, name, modtime, sizeFunc, content)
}

相比 io.Copyhttp.ServeContent 可以自动计算响应的内容长度、可以自动识别内容的MIME类型,还可以处理If-Match,If-Unmodified-Since,If-None-Match,If-Modified-Since和If-Range的要求。

因为 * os.File 实现了 io.ReadSeeker 接口,所以我们可以直接使用文件的内容。

小结

好了,到了这里,我们已经分析完了Negroni中静态文件处理中间件的实现,看完后相信你也可以写自己的静态文件处理服务了,可以自己试试,写一个和 http.FileServer 类似功能的静态文件处理服务。

本文为原创文章,转载注明出处,欢迎扫码关注公众号 flysnow_org 或者网站 http://www.flysnow.org/ ,第一时间看后续精彩文章。觉得好的话,顺手分享到朋友圈吧,感谢支持。

Go语言中间件框架 Negroni 的静态文件处理源码分析


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

ggplot2:数据分析与图形艺术

ggplot2:数据分析与图形艺术

哈德利·威克姆 (Hadley Wickham) / 统计之都 / 西安交通大学出版社 / 2013-5-1 / CNY 46.00

中译本序 每当我们看到一个新的软件,第一反应会是:为什么又要发明一个新软件?ggplot2是R世界里相对还比较年轻的一个包,在它之前,官方R已经有自己的基础图形系统(graphics包)和网格图形系统(grid包),并且Deepayan Sarkar也开发了lattice包,看起来R的世界对图形的支持已经足够强大了。那么我们不禁要问,为什么还要发明一套新的系统? 设计理念 打个比......一起来看看 《ggplot2:数据分析与图形艺术》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具