Go语言Web框架gwk介绍 (一)

今天看到Golang排名到前30名了,看来关注的人越来越多了,接下来几天详细介绍Golang一个web开发框架GWK。

现在博客园支持markdown格式发布文章么?后台的编辑器不太好用嘛。

 

GWK

简介

gwk(GO Web Server Kit)是GO语言的Web Server开发框架,简单易用,扩展性好,而且兼容Go App Engine。

安装

gwk只支持GO 1.1+版本,安装GO 1.1后,运行下面的命令即可。

go get github.com/sdming/wk

gwk依赖kiss和mcache两个package,如果没有自动安装成功的话,可以单独运行下面的命令安装:

go get github.com/sdming/kiss  
go get github.com/sdming/mcache  

示例

gwk的文档比较简单,写的不是很详细,自带的demo写的比较全,主要的功能点都涉及到了。

另外Google App Engine上有一个展示gwk demo的网站,是用gwk框架搭建的,也是一个了解gwk的地方。网址是[http://gwk-demo.appspot.com]。 需要注意的是,这个demo网站的示例数据是放在内存的,多用户访问时会互相影响 。另外App Engine会自动管理服务实例以及会根据访问情况自动关闭或启动服务,示例数据也会受到影响。

启动服务

gwk不像revel那样是一个Web Server框架,需要自己写代码来启动gwk的服务。最简单的方式如下。

server, err := wk.NewDefaultServer()if err != nil {fmt.Println("NewDefaultServer error", err)return
}server.RouteTable.Get("/data/top/{count}").To(...)server.Start()

基本步骤就是:

  • 创建HttpServer示例
  • 注册路由
  • 调用Start方法监听Http端口

接下来详细介绍gwk各个功能模块的用法,先从路由开始。

路由

gwk用RouteTable来存储注册的路由,RouteTable的定义如下:

type RouteTable struct {Routes []*RouteRule
}

当gwk接收到http请求时,按照顺序遍历RouteRule直到找到匹配的Route,如果没有找到则返回404。

RouteRule的定义如下:

type RouteRule struct {// Methos is http method of requestMethod string// Pattern is path patternPattern string// Handler process requestHandler Handler
}

Method是Http method,比如:GET, POST, PUT, DELETE,*代表匹配所有的http method。
Pattern是URL匹配的模式,具体的格式下面再讲。
Handler是用来处理请求的代码,是一个接口,定义如下:

type Handler interface {Execute(ctx *HttpContext)
}

gwk提供了若干方法来注册路由。一个最简单的方法是路由到一个func (*wk.HttpContext) (wk.HttpResult, error) 类型的函数,比如:

// url: /data/top/10
server.RouteTable.Get("/data/top/{count}").To(DataTopHandle)

上面的代码将GET /data/top/10这样的request path注册到一个func (*wk.HttpContext) (wk.HttpResult, error)类型的函数,例子中DataTopHandle的定义如下:

func DataTopHandle(ctx *wk.HttpContext) (result wk.HttpResult, err error) {if count, ok := ctx.RouteData.Int("count"); !ok {err = errors.New("parameter invalid:" + "count")} else {data := DataTop(count)result = wk.Json(data)}return
}

例子中HttpContext是这次http请求的一个封装,HttpResult是这次请求返回的数据,详细的定义在下面会介绍。

通过RouteData可以获得在request path中匹配到的参数,比如上面的{count}参数,RouteData的定义如下:

type RouteData map[string]string

RouteData提供了若干方法来简化Route参数的读取。

读取整数

func (r RouteData) Int(name string) (int, bool)

读取整数,如果参数不存在或者不是有效的整数格式则返回一个缺省值

func (r RouteData) IntOr(name string, v int) int

类似的方法还有

Bool,BoolOr,Float,FloatOr,Str,StrOr

asp.net mvc 的开发人员应该会对"/data/top/{count}"这样的路由规则写法比较熟悉,gwk支持两种路由规则的写法。

  • 正则表达式

    ^/user/?(?P<action>[[:alnum:]]+)?/?(?P<arg>[[:alnum:]]+)?/?
    

    匹配类似/user/view/1这样的request path

  • 正则表达式写起来比较麻烦,而且执行速度慢,你也可以用类似asp.net mvc的写法,比如

    "/data/top/{count}"   
    "/query/{year}-{month}-{day}"   
    "/basic#/{action}/{id}"   
    "/data/int/{p0}?"   
    "/data/range/{p0}-{p1}"   
    

    规则很简单,前缀匹配requets path,{}匹配的内容会被提取为参数。其中两个特殊字符需要介绍一下。

    • "#"字符代表精确匹配#之前的内容,#之后的为可选匹配,比如/basic和/basic/add,/basic/delete/1都匹配上面规则。
    • "?"字符代表匹配request path的结束,比如/data/int/1匹配上面的规则,/data/int/1/foo就不符合上面的规则。

gwk还提供了其他的方式来注册路由。

通过ToFunc方法注册路由到一个普通函数,比如

// url: /data/int/1
server.RouteTable.Get("/data/int/{p0}?").ToFunc(model.DataByInt)func DataByInt(i int) *Data {if i < 0 {i = 0}return newData(i)
}

再比如

// url: /data/range/1-9
server.RouteTable.Get("/data/range/{p0}-{p1}").ToFunc(model.DataByIntRange)func DataByIntRange(start, end int) []*Data {data := make([]*Data, 2)data[0] = newData(start)data[1] = newData(end)return data
}

因为GO的反射不能获得函数参数的名字,所以这里用p0,p1,p2...来代表函数的第0,1,2...个参数。

gwk会根据http请求中accept的内容来自动决定返回数据的格式,上面的例子中Data定义如下:

type Data struct {Str   stringUint  uint64Int   intFloat float32Byte  byte
}

如果Request的Accept中包含字符串"xml",则结果序列化为xml格式,如果包含"jsonp",则结果序列化为jsonp,如果包含json,则序列化为json格式,详细信息可以参考下面的"格式化"一节

除了上面的p0,p1,p2指定参数的方式,可以用BindByNames按照名字来绑定函数的参数,比如:

// url: /data/name/1
server.RouteTable.Get("/data/name/{id}").ToFunc(model.DataByInt).BindByNames("id")

上面的代码告诉gwk,路由参数"id"是函数DataByInt的第一个参数。

// url: /data/namerange/1-9
server.RouteTable.Get("/data/namerange/{start}-{end}").ToFunc(model.DataByIntRange).BindByNames("start", "end")

上面的代码告诉gwk,路由参数"start","end"是函数DataByIntRange的第一个和第二个参数。

也可以绑定到querypath或者form中的参数,比如:

// url: /data/namerange/?start=1&end=9
server.RouteTable.Get("/data/namerange/").ToFunc(model.DataByIntRange).BindByNames("start", "end")

再比如:

// url: get /data/set?str=string&uint=1024&int=32&float=3.14&byte=64
server.RouteTable.Get("/data/set?").ToFunc(model.DataSet).BindByNames("str", "uint", "int", "float", "byte")func DataSet(s string, u uint64, i int, f float32, b byte) *Data {return &Data{Str:   s,Uint:  u,Int:   i,Float: f,Byte:  b,}
}

如果参数比较多,一个合适的方法是将参数定义为一个struct,然后调用BindToStruct来绑定参数。比如:

// url: post /data/post?
// form:{"str": {"string"}, "uint": {"1024"}, "int": {"32"}, "float": {"1.1"}, "byte": {"64"}}
server.RouteTable.Post("/data/post?").ToFunc(model.DataPost).BindToStruct()func DataPost(data Data) string {return data.String()
}// url: post /data/postptr?
// form:{"str": {"string"}, "uint": {"1024"}, "int": {"32"}, "float": {"1.1"}, "byte": {"64"}}
server.RouteTable.Post("/data/postptr?").ToFunc(model.DataPostPtr).BindToStruct()func DataPostPtr(data *Data) string {return data.String()
}

如果觉得每个函数定义一个参数对象比较麻烦,也可以用匿名对象:

server.RouteTable.Get("/data/anonymous?").ToFunc(DataAnonymous).BindToStruct()func DataAnonymous(data struct {Str   stringUint  uint64Int   intFloat float32Byte  byte
},) string {return fmt.Sprintln(data)
}

更方便的路由方式是注册一个到controller的路由,在controller一节会介绍。

格式化

gwk会根据http请求中accept的内容来自动决定返回数据的格式,如果Request的Accept中包含字符串"xml",则结果序列化为xml格式,如果包含"jsonp",则结果序列化为jsonp,如果包含json,则序列化为json格式。具体的例子可以看http://gwk-demo.appspot.com/doc/routedemo

你也可以通过设置Formatter来指定输出的格式,Formatter的定义如下

type FormatFunc func(*HttpContext, interface{}) (HttpResult, bool)

gwk默认支持两种序列化方式,xml和json。比如:

// url: /data/int/1/xml
server.RouteTable.Get("/data/int/{p0}/xml").ToFunc(model.DataByInt).ReturnXml()// url: /data/int/1/json
server.RouteTable.Get("/data/int/{p0}/json").ToFunc(model.DataByInt).ReturnJson()

ReturnXml指定DataByInt的返回值格式化为xml,ReturnJson指定DataByInt的返回值格式化为json。

你也可以自定义序列化的方式,比如:

// url: /data/int/1/kson
server.RouteTable.Get("/data/int/{p0}/kson").ToFunc(model.DataByInt).Return(formatKson)func formatKson(ctx *wk.HttpContext, x interface{}) (wk.HttpResult, bool) {b, _ := kson.Marshal(x)return wk.Content(string(b), "text/plain"), true
}

kson格式是gwk的配置文件采用的格式,后文会详细介绍,上面的代码返回的数据如下:

{Str:string:1Uint:100Int:10Float:1.1Byte:1
}

gwk还提供了注册全局FormatFunc的地方:

type FormatList []FormatFunc
var Formatters FormatList

你可以通过增删Formatters或者修改Formatters的顺序来调整默认的格式化方式。

Controller

当需要注册的路由方法比较多,而且之间有一定的逻辑关系时,可以定义一个类似的asp.net mvc的Controller对象,然后将路由指向这个对象。代码可以参考https://github.com/sdming/wk/blob/master/demo/basic/controller/basic.go

一个简单的注册Controller的例子如下:

basic = NewBasicController()// url: /basic/xxx/xxx
server.RouteTable.Path("/basic#/{action}/{id}").ToController(basic)

用正则表达式的话,例子如下

srv.RouteTable.Regexp("*", "^/user/?(?P<action>[[:alnum:]]+)?/?(?P<arg>[[:alnum:]]+)?/?").ToController(NewUserController())

注册到controller的路由,一个特殊的路由参数是{action},它指定了调用Controller的哪一个方法。比如/basic/delete/32对应的action是"delete",调用controller的delete方法,一个例子如下:

// url: /basic/delete/32
func (c *BasicController) Delete(ctx *wk.HttpContext) (result wk.HttpResult, err error) {l := len(c.data)if i, ok := ctx.RouteData.Int("id"); ok {c.deleteByInt(i)}return wk.Data(l - len(c.data)), nil
}

gwk现在版本的controller只支持func (ctx *wk.HttpContext) (result wk.HttpResult, err error)类型的方法,已经基本够用了。

再看一个例子:

// url: /basic/add/?int=32&str=string&uint=1024&float=1.1&byte=64
func (c *BasicController) Add(ctx *wk.HttpContext) (result wk.HttpResult, err error) {data := &model.Data{Int:   ctx.FormIntOr("int", 0),Uint:  uint64(ctx.FormIntOr("uint", 0)),Str:   ctx.FormValue("str"),Float: float32(ctx.FormFloatOr("float", 0.0)),Byte:  byte(ctx.FormIntOr("byte", 0)),}c.data = append(c.data, data)return wk.Data(data.String()), nil
}

FormIntOr,FormFloatOr等函数是为了方便读取Request Form数据,可以参考RouteData的对应函数。

wk.Data函数返回 *DataResult对象,*DataResult实现了wk.HttpResult接口, HttpResult接口的详细介绍见后面的章节。

func Data(data interface{}) *DataResult {return &DataResult{Data: data,}
}

再看一个返回json数据的例子

// url: /basic/int/32
func (c *BasicController) Int(ctx *wk.HttpContext) (result wk.HttpResult, err error) {if id, ok := ctx.RouteData.Int("id"); ok {return wk.Json(c.getByInt(id)), nil}return wk.Data(""), nil
}

再看一个直接读取post的数据,解析成json的例子:

// url: post /basic/post
func (c *BasicController) Post(ctx *wk.HttpContext) (result wk.HttpResult, err error) {var body []byteif body, err = ctx.ReadBody(); err != nil {return nil, err}data := &model.Data{}err = json.Unmarshal(body, data)if err != nil {return nil, err}c.data = append(c.data, data)return wk.Data(true), nil
}

如果没有找到路由参数{action},gwk会将http method作为action,也就是把"get","post","delete"作为action,如果找不到对应的方法,会将{action}{method}组合起来作为action,这在一些场合还是比较实用的,如果还找不到对应的方法,则将"default"作为action,如果还是找不到对应的方法,则返回404.

各种流行的MVC类开发框架比较多,controller应该不用做过多的介绍,接下来介绍HttpResult接口。

转载于:https://www.cnblogs.com/buzzlight/p/gwk_basic_01.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/547581.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3D手势姿态跟踪算法:手机端实时检测,多个手势同时捕捉

就在不久前&#xff0c;Google 人工智能实验室宣布&#xff0c;他们在「实时手部跟踪」方面取得了新的进展&#xff0c;并将这项新技术运用在了 MediaPipe 中&#xff0c;这也是 AI 计算机视觉任务的一大突破。这一技术不光可以在手机上实现实时捕捉性能&#xff0c;甚至可以同…

Windows服务的快速搭建与调试(C#图解)

目录 一、什么是Windows 服务&#xff1f; 二、创建Windows 服务与安装/卸载批处理。 三、调试Windows 服务。 正文 一、什么是Windows 服务&#xff1f; 答&#xff1a;Microsoft Windows 服务&#xff08;即&#xff0c;以前的 NT 服务&#xff09;使您能够创建在它们自…

使用 JMeter 进行API接口压力测试

使用 JMeter 进行API接口压力测试 一.前言 压力测试是每一个Web应用程序上线之前都需要做的一个测试&#xff0c;他可以帮助我们发现系统中的瓶颈问题&#xff0c;减少发布到生产环境后出问题的几率&#xff1b;预估系统的承载能力&#xff0c;使我们能根据其做出一些应对措施…

ser,ver

friend_conservation_bgfriend_conversation_bg.png, [self.bgButtonsetBackgroundImage:[[UIImageimageNamed:"conversation_bg.png"] stretchableImageWithLeftCapWidth:10topCapHeight:30] forState:UIControlStateNormal]; xy方向 找 两根线 来 拉伸&#xff0c;…

linux 删除node进程,关于node.js:杀死Linux中的节点进程

尝试使用节点server.js运行节点服务器时&#xff0c;我收到侦听EADDRINUSE ::: 4002的错误。 我通过以下命令在端口4002上监听进程&#xff1a;sudo lsof -i&#xff1a;4002。 之后&#xff0c;我尝试使用kill -9终止进程。 问题是当我在终止进程后再次运行sudo lsof -i&#…

MS SQL查询库、表、列数据结构信息汇总

前言 一般情况我们下&#xff0c;我们是知道数据库的表、列信息的&#xff08;因为数据库是我们手动设计&#xff09;&#xff0c;但特殊情况下&#xff0c;如果你只能拿到数据库连接信息&#xff0c;也就是知道的一个数据库名的情况下&#xff0c;你要怎么得到它下面的所有表…

linux 程序占内存,linux下,一个运行中的程序,究竟占用了多少内存

1. 在linux下&#xff0c;查看一个运行中的程序&#xff0c; 占用了多少内存&#xff0c; 通常的命令有php(1). ps aux&#xff1a;html其中 VSZ(或VSS)列 表示&#xff0c;程序占用了多少虚拟内存。linuxRSS列 表示&#xff0c; 程序占用了多少物理内存。ios虚拟内存能够不用…

C#常用代码汇总

1、字符串首字母转为大写。 System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase("字符串"); 2、winform选取文件及文件夹。 // 选取文件OpenFileDialog openFileDialog new OpenFileDialog();openFileDialog.Filter "文本文件|*.*|C#文件…

如何搭建一个完整的Vue3.0 + ts 的项目

如何搭建一个完整的Vue3.0 ts 的项目 相信9月18日尤大大的关于Vue3.0的发表演讲大家一定有所关注,现在Vue3.0 也已经进入RC阶段&#xff08;最终产品的候选版本&#xff0c;如果没有问题则可发布成为正式版本&#xff09;。所以Vue3.0的学习是我们必然的趋势&#xff0c;今天&…

C#下2\10\16进制互转代码总汇

1、十进制转换其他&#xff1a;Convert.ToString(十进制数字, 2|8|16进制模式) //十进制转二进制Convert.ToString(69, 2);//十进制转八进制Convert.ToString(69, 8);//十进制转十六进制Convert.ToString(69, 16); 2、其他进制转换十进制&#xff1a;Convert.ToInt32(待转换数…

手机客户端和服务器端通信

2019独角兽企业重金招聘Python工程师标准>>> 手机客户端与服务器端的通信&#xff0c;不同于浏览器与服务器端的通信。浏览器和服务器端的通信依靠session去维持一个会话&#xff0c; 当这一切搬到手机上仿佛一切都失效了。 1.在上一家公司的时候公司同事曾经问过我…

linux下boot文件是什么文件,Boot.ini是什么文件?Boot.ini文件在哪里

Boot.ini 文件是系统启动引导程序文件&#xff0c;装多系统或者重装系统的时候会用到它。因此&#xff0c;由于系统启动而造成的问题也不在少数&#xff0c;那Boot.ini是什么文件呢&#xff1f;Boot.ini文件在哪里&#xff1f;下面就跟小编一起去了解一下吧&#xff01;步骤如下…

Kubeflow使用Kubernetes进行机器学习GPU分布式训练

Kubeflow使用Kubernetes进行机器学习 Kubeflow是Google推出的基于kubernetes环境下的机器学习组件&#xff0c;通过Kubeflow可以实现对TFJob等资源类型定义&#xff0c;可以像部署应用一样完成在TFJob分布式训练模型的过程。最初的设计是将Kubernetes和Tensorflow结合实现对Te…

Net操作配置文件(Web.config|App.config)通用类

一、Net操作web.config通用类&#xff08;代码如下&#xff09;&#xff1a; using System;using System.Configuration;using System.Web;using System.Web.Configuration;/// ConfigurationOperator 的摘要说明public class ConfigurationOperator : IDisposable{private Con…

hibernate 程序运行时的错误,及解决办法(不定期更新)

这个错误是因为&#xff1a;没有配置hibernate.cfg.xml中的最后一项 <mapping resource"org/hibernate/first/model/Student.hbm.xml"/>这个错误是因为&#xff1a;在配置hibernate缓存的时候出的错&#xff0c;我就把我这个缓存代码删除掉了。代码如下<pro…

嵌入式linux设计师,make在linux——《嵌入式linux设计与应用》

程序模块的内部关系决定了源程序编译和链接的顺序。通过建立makefile可以描述模块间的 相互依赖关系。make命令从中读取这些信息&#xff0c;然后根据这些信息对程序进行管理和维护。在makefile 里主要提供的是有关目的文件与依靠文件之间的关系&#xff0c;还指明了用什么命令…

kubernetes集群使用GPU及安装kubeflow1.0.RC操作步骤

kubernetes集群使用GPU及安装kubeflow1.0.RC操作步骤 Kubeflow使用场景 希望训练tensorflow模型且可以使用模型接口发布应用服务在k8s环境中(eg.local,prem,cloud) 希望使用Jupyter notebooks来调试代码&#xff0c;多用户的notebook server 在训练的Job中&#xff0c;需要对…

T-Sql备份还原数据库

代码如下&#xff1a; -- 备份数据库BACKUP DATABASE 数据库名称 TO DISK 物理存储位置 WITH FORMAT,CHECKSUM -- 还原数据库alter database 数据库名称 set offline with rollback immediate -- 设置数据库脱机RESTORE FILELISTONLY From disk 待还原文件地址 --查询待…

PHP拦截器的使用(转)

PHP有如下几个拦截器&#xff1a; 1、__get($property)功能&#xff1a;访问未定义的属性是被调用2、__set($property, $value)功能&#xff1a;给未定义的属性设置值时被调用3、__isset($property)功能&#xff1a;对未定义的属性调用isset()时被调用4、__unset($property)功能…

linux线程负载,linux 排查cpu负载过高异常(转载)

问&#xff1a;如何定位是哪个服务进程导致CPU过载&#xff0c;哪个线程导致CPU过载&#xff0c;哪段代码导致CPU过载&#xff1f;步骤一、找到最耗CPU的进程工具&#xff1a;top方法&#xff1a;执行top -c &#xff0c;显示进程运行信息列表键入P (大写p)&#xff0c;进程按照…