Go Web学习(2)——实现中间件(middleware)
昨天我们探讨了Go语言使用标准库实现简单的web版的HelloWorld,大致了解了Go实现server应用的流程,今天我们来探讨一下用Go语言实现http的Middleware。
我们知道,绝大部分web应用会将逻辑与功能的实现写在middleware里面更整个结构更加分明,middleware大致在web应用里面大致分为两种,即处理response和处理request(个人拙见,如有错误请以指正),接下来我将以处理request请求的形式来实现两种middleware的写法。
第一种 以类型的形式实现
上篇博客中,我们探讨过Go语言实现Web最核心的部分:
http.ListenAndServe(":8000", handler)
复制代码
http包里面的ListenAndServe函数接受两个参数,即监听地址和处理接口handler,handler是一个接口,我们需要实现这个接口中的唯一方法ServeHTTP便可以实现上述的函数,因此我们处理的整个逻辑和流程都会在这个handler里面,下面我们先来看一个最简单的handler实现。
package mainimport ("net/http"
)func myHandler(w http.ResponseWriter, r *http.Request) {w.Write([]byte("Hello World"))
}func main() {http.ListenAndServe(":8000", http.HandlerFunc(myHandler))
}
复制代码
上面的代码中我们定义一个myHandler,它接受http.ResponseWriter,*http.Request两个参数然后再向ResponseWriter中写入Hello World,在main函数中,我们直接使用了ListenAndServe方法监听本地的8000端口,注意由于Go语言的强类型性,ListenAndServe的第二个参数类型是Handler,因此我们想要将myHandler传递给ListenAndServe就必须实现ServeHTTP这个方法。但其实Go源码里面已经帮我们实现了这个方法。
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {f(w, r)
}
复制代码
可以看到,Go语言将func(ResponseWriter, *Request)这种类型的函数直接定义了类型HandlerFunc,而且还实现了ServeHTTP这个方法,但是这个方法本身并没有实现任何逻辑,需要我们自己来实现。因此我们实现了myHandler这个方法,它将输出一个最简单的HelloWorld响应。随后我们可以用curl来测试一下:
$ curl localhost:8000
Hello World
复制代码
可以看到,我们通过curl请求本地的8000端口,返回我们一个HelloWorld。这便是一个最简单的Handler实现了。但是我们的目标是实现中间件,有了上述的所采用的的方法我们就可以大致明白,myHandler应该作为最后的调用,在它之前才是中间件应该作用的地方,那么我们有了一个大致的方向,我们可以实现一个逻辑用来包含这个myHandler,但它本身也必须实现Handler这个接口,因为我们要把它传递给ListenAndServe这个方法。好,我们先大致阐述一下这个中间件的作用,它会拦截一切请求除了这个请求的host是我们想要的host,当然这个host有我们定义。
type SingleHost struct {handler http.HandlerallowedHost string
}
复制代码
于是我们定义了一个SingleHost的结构体,它里面有两个成员一个是Handler,它将是我们上述的myHandler,另一个是我们允许来请求Server的用户,这个用户他有唯一的Host,只有当他的Host满足我们的要求是才让他请求成功,否则一律返回403。
因为我们需要将这个SingleHost实例化并传递给ListenAndServe这个方法,因此它必须实现ServeHTTP这个方法,所以在ServeHTTP里面可以直接定义我们用来实现中间件的逻辑。即除非来请求的用户的Host是allowedHost否则一律返回403。
func (this *SingleHost) ServeHTTP(w http.ResponseWriter, r *http.Request) {if (r.Host == this.allowedHost) {this.handler.ServeHTTP(w, r)} else {w.WriteHeader(403)}
}
复制代码
好,可以清楚的看到只有Request的Host==allowedHost的时候,我们才调用handler的ServeHTTP方法,否则返回403.下面是完整代码:
package mainimport ("net/http"
)type SingleHost struct {handler http.HandlerallowedHost string
}func (this *SingleHost) ServeHTTP(w http.ResponseWriter, r *http.Request) {if (r.Host == this.allowedHost) {this.handler.ServeHTTP(w, r)} else {w.WriteHeader(403)}
}func myHandler(w http.ResponseWriter, r *http.Request) {w.Write([]byte("Hello World"))
}func main() {single := &SingleHost{handler:http.HandlerFunc(myHandler),allowedHost:"refuse.com",}http.ListenAndServe(":8000", single)
}复制代码
然后我们用curl来请求本地的8000端口,
$ curl --head localhost:8000
HTTP/1.1 403 Forbidden
Date: Sun, 21 Jan 2018 08:32:47 GMT
Content-Type: text/plain; charset=utf-8
复制代码
可以看到我们在中间件中实现了只允许host为refuse.com来访问的逻辑实现了,由于curl的Host是localhost所以我们的服务器直接返回了它一个403。接下来我们改变一下allowedHost
allowedHost:"localhost:8000",
复制代码
我们将allowedHost变成为localhost:8000,然后用curl测试
$ curl localhost:8000
Hello World
复制代码
可以看到curl通过了中间件的并直接获得了myHandler返回的HelloWorld。
第二种 以函数的形式实现
好,在上面我们实现了以类型为基础的中间件,可能对Node.js较熟悉的人都习惯以函数的形式实现中间件。首先,因为我们是以函数来实现中间件的因此这个函数返回的便是Handler,它会接受两个参数,一个是我们定义的myHandler,一个是allowedHost。
func SingleHost(handler http.Handler, allowedHost string) http.Handler {fn := func(w http.ResponseWriter, r *http.Request) {if r.Host == allowedHost {handler.ServeHTTP(w, r)} else {w.WriteHeader(403)}}return http.HandlerFunc(fn)
}
复制代码
可以看到,我们在函数内部定义可一个匿名函数fn,这个匿名函数便是我们要返回的Handler,如果请求用户的Host满足allowedHost,便可以将调用myHandler的函数返回,否则直接返回一个操作403的函数。整个代码如下:
package mainimport "net/http"func SingleHost(handler http.Handler, allowedHost string) http.Handler {fn := func(w http.ResponseWriter, r *http.Request) {if r.Host == allowedHost {handler.ServeHTTP(w, r)} else {w.WriteHeader(403)}}return http.HandlerFunc(fn)
}func myHandler(w http.ResponseWriter, r *http.Request) {w.Write([]byte("Hello World"))
}func main() {single := SingleHost(http.HandlerFunc(myHandler), "refuse.com")http.ListenAndServe(":8000", single)
}
复制代码
我们还是通过curl来测试一下
$ curl --head localhost:8000
HTTP/1.1 403 Forbidden
Date: Sun, 21 Jan 2018 08:45:39 GMT
Content-Type: text/plain; charset=utf-8
复制代码
可以看到由于不满足refuse.com的条件,我们会得到一个403,让我们将refuse.com改为localhost:8000测试一下。
$ curl localhost:8000
Hello World
复制代码
与刚才一样我们得到了HelloWorld这个正确结果。好,我们通过以函数的形式实现了上面同样的功能,当然,这两种方法都可行,主要看个人喜好了,喜欢函数式编程的我还是喜欢后者(笑)。今天就到这里了,祝掘金越办越好!!!
Go Web学习(2)——实现中间件(middleware)相关推荐
- React学习笔记——redux里中间件Middleware的运行机理
1.前言 上篇文章中,我们详细介绍了redux的相关知识和如何使用,最后使用中间件Middleware来帮助我们完成异步操作,如下图 上面是很典型的一次 redux 的数据流的过程,在增加了 midd ...
- ASP.NET Core中间件(Middleware)实现WCF SOAP服务端解析
ASP.NET Core中间件(Middleware)进阶学习实现SOAP 解析. 本篇将介绍实现ASP.NET Core SOAP服务端解析,而不是ASP.NET Core整个WCF host. 因 ...
- Laravel核心解读--中间件(Middleware)
中间件(Middleware)在Laravel中起着过滤进入应用的HTTP请求对象(Request)和完善离开应用的HTTP响应对象(Reponse)的作用, 而且可以通过应用多个中间件来层层过滤请求 ...
- Django基础(33): 中间件(middleware)的工作原理和应用场景举例
在初级Django开发项目中,你大概率用不到中间件(Middleware).但随着项目需求越来越复杂,你就需要开始编写自己的中间件了.当你了解到Django中间件(middleware)的工作原理和作 ...
- C# Owin 创建与测试自己的中间件Middleware
本文纯属介绍怎么简单地创建自己的Owin.还没有理解owin概念的请看上一篇文章:http://www.cnblogs.com/alunchen/p/7049307.html 目录 1.创建项目 2. ...
- 学习 | egg.js 中间件和插件
小小又开始学习了,这次学习的是中间件和插件. 这次将会对这两个点,进行学习. 中间件 对于egg.js 来说,中间件和express的中间件性质相似,和洋葱模型类似. 这里首先讲解的是egg.js的中 ...
- (学习笔记)laravel 中间件
(学习笔记)laravel 中间件 laravel的请求在进入逻辑处理之前会通过http中间件进行处理. 也就是说http请求的逻辑是这样的: 建立中间件 首先,通过Artisan命令建立一个中间件. ...
- 暑期沉淀web学习——php基础
web学习流程框架 概念理解 数据流向:从前端收集完数据之后,发送给中间件,将请求报文变成机器可以直接执行的一连串的代码,再交给后端语言处理程序,从数据库取出数据. PHP基础 PHP概况 PHP优势 ...
- Django 中间件(middleware)的工作原理和应用场景举例
在初级Django开发项目中,你大概率用不到中间件(Middleware).但随着项目需求越来越复杂,你就需要开始编写自己的中间件了.当你了解到Django中间件(middleware)的工作原理和作 ...
- python middleware_Django框架之中间件MiddleWare的实现
Django中的中间件是一个轻量级.底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出. 中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的 ...
最新文章
- 自动驾驶出行,进入下半场
- Cocos2d-x列表嵌套裁剪bug
- iOS经典面试题之“runtime是如何实现weak变量的自动置nil”
- 区块链 HyperLedger Fabric安装
- Springboot只允许进入登录注册的页面,没登录页面进行拦截。
- 1-2-05:填空:类型转换2
- 贝叶斯深度神经网络_深度学习为何胜过贝叶斯神经网络
- Asterisk拨号方案常用函数说明
- 关注BLUEBEE的浏览器发展
- Object C数据类型
- fit函数 model_深度学习与Tensorflow学习笔记2 ——回调函数callbacks和Tensorboard
- iOS6、7、8、9新特性汇总和适配说明
- 吴恩达神经网络和深度学习-学习笔记-27-多任务学习
- Atitit 技术经理 技术总裁 cto 技术总监 职责与流程表总结 v4 t88.docx Atitit 技术总裁 cto 技术总监 技术经理职责与流程表总结 1. 人事财物 文化精神
- windows与linux线程,Linux和Windows两种风格的操作系统,创建线程的方式有何不同?...
- Java中判断String不为空的问题性能比较
- Rufus 制作U盘启动器
- 惠普1139一体打印机如何联网打印_惠普1139 惠普1139打印扫描一体机功能
- 电子档案管理系统java,电子档案管理系统单点登陆示例
- PostgreSql对比MySQL优势
热门文章
- 怎么自学python 知乎-你是如何自学 Python 的?
- python xpath语法-Python爬虫之XPath语法
- python怎么识别拼音-python获取一组汉字拼音首字母的方法
- python怎么安装numpy库-Python NumPy库安装使用笔记
- php多规格多价格,不同规格的不同价格是怎么实现的呢?? 看这里
- java swing开源组件_Squareness
- Django 的反向解析与有无名分组
- asp.net采用OLEDB方式导入Excel数据时提示:未在本地计算机上注册Microsoft.Jet.OLEDB.4.0 提供程序...
- (转载)文件系统与数据库系统的区别
- Java+eclipse的配置