mux路由_使用大猩猩/ mux进行HTTP请求路由和验证
mux路由
Go网络库包括http.ServeMux
结构类型,该结构类型支持HTTP请求多路复用(路由):Web服务器将对带有URI的托管资源的HTTP请求(如/ sales4today)路由到代码处理程序; 处理程序在发送HTTP响应(通常为HTML页面)之前执行适当的逻辑。 这是该架构的草图:
+------------+ +--------+ +---------+
HTTP request---->| web server |---->| router |---->| handler |
+------------+ +--------+ +---------+
调用
ListenAndServe方法以启动HTTP服务器
http . ListenAndServe ( ":8888" , nil ) // args: port & router
第二个参数nil
表示DefaultServeMux
用于请求路由。
gorilla/mux
包具有mux.Router
类型,以替代DefaultServeMux
或自定义请求多路复用器。 在ListenAndServe
调用中, mux.Router
实例将nil
替换为第二个参数。 通过代码示例可以很好地说明mux.Router
如此吸引人的原因:
1.一个示例Crud Web应用程序
Crud Web应用程序(请参见下文)支持四个CRUD(创建读取更新删除)操作,这些操作与四个HTTP请求方法相匹配:分别为POST,GET,PUT和DELETE。 在crud应用程序中,托管资源是一列陈词滥调对,每个陈词滥调和一个冲突的陈词滥调,例如这对:
Out of sight, out of mind. Absence makes the heart grow fonder.
可以添加新的陈词滥调对,而现有的可以被编辑或删除。
Crud Web应用程序
package main
import (
"gorilla/mux"
"net/http"
"fmt"
"strconv"
)
const GETALL string = "GETALL"
const GETONE string = "GETONE"
const POST string = "POST"
const PUT string = "PUT"
const DELETE string = "DELETE"
type clichePair struct {
Id int
Cliche string
Counter string
}
// Message sent to goroutine that accesses the requested resource.
type crudRequest struct {
verb string
cp * clichePair
id int
cliche string
counter string
confirm chan string
}
var clichesList = [] * clichePair {}
var masterId = 1
var crudRequests chan * crudRequest
// GET /
// GET /cliches
func ClichesAll ( res http . ResponseWriter , req * http. Request ) {
cr := &crudRequest { verb : GETALL , confirm : make ( chan string )}
completeRequest ( cr , res , "read all" )
}
// GET /cliches/id
func ClichesOne ( res http . ResponseWriter , req * http. Request ) {
id := getIdFromRequest ( req )
cr := &crudRequest { verb : GETONE , id : id , confirm : make ( chan string )}
completeRequest ( cr , res , "read one" )
}
// POST /cliches
func ClichesCreate ( res http . ResponseWriter , req * http. Request ) {
cliche , counter := getDataFromRequest ( req )
cp := new ( clichePair )
cp . Cliche = cliche
cp . Counter = counter
cr := &crudRequest { verb : POST , cp : cp , confirm : make ( chan string )}
completeRequest ( cr , res , "create" )
}
// PUT /cliches/id
func ClichesEdit ( res http . ResponseWriter , req * http. Request ) {
id := getIdFromRequest ( req )
cliche , counter := getDataFromRequest ( req )
cr := &crudRequest { verb : PUT , id : id , cliche : cliche , counter : counter , confirm : make ( chan string )}
completeRequest ( cr , res , "edit" )
}
// DELETE /cliches/id
func ClichesDelete ( res http . ResponseWriter , req * http. Request ) {
id := getIdFromRequest ( req )
cr := &crudRequest { verb : DELETE , id : id , confirm : make ( chan string )}
completeRequest ( cr , res , "delete" )
}
func completeRequest ( cr * crudRequest , res http . ResponseWriter , logMsg string ) {
crudRequests< - cr
msg := < - cr . confirm
res . Write ([] byte ( msg ))
logIt ( logMsg )
}
func main () {
populateClichesList ()
// From now on, this gorountine alone accesses the clichesList.
crudRequests = make ( chan * crudRequest , 8 )
go func () { // resource manager
for {
select {
case req := < - crudRequests :
if req . verb == GETALL {
req . confirm< - readAll ()
} else if req . verb == GETONE {
req . confirm< - readOne ( req . id )
} else if req . verb == POST {
req . confirm< - addPair ( req . cp )
} else if req . verb == PUT {
req . confirm< - editPair ( req . id , req . cliche , req . counter )
} else if req . verb == DELETE {
req . confirm< - deletePair ( req . id )
}
}
}()
startServer ()
}
func startServer () {
router := mux . NewRouter ()
// Dispatch map for CRUD operations.
router . HandleFunc ( "/" , ClichesAll ) . Methods ( "GET" )
router . HandleFunc ( "/cliches" , ClichesAll ) . Methods ( "GET" )
router . HandleFunc ( "/cliches/{id:[0-9]+}" , ClichesOne ) . Methods ( "GET" )
router . HandleFunc ( "/cliches" , ClichesCreate ) . Methods ( "POST" )
router . HandleFunc ( "/cliches/{id:[0-9]+}" , ClichesEdit ) . Methods ( "PUT" )
router . HandleFunc ( "/cliches/{id:[0-9]+}" , ClichesDelete ) . Methods ( "DELETE" )
http . Handle ( "/" , router ) // enable the router
// Start the server.
port := ":8888"
fmt . Println ( " \n Listening on port " + port )
http . ListenAndServe ( port , router ); // mux.Router now in play
}
// Return entire list to requester.
func readAll () string {
msg := " \n "
for _ , cliche := range clichesList {
next := strconv . Itoa ( cliche . Id ) + ": " + cliche . Cliche + " " + cliche . Counter + " \n "
msg += next
}
return msg
}
// Return specified clichePair to requester.
func readOne ( id int ) string {
msg := " \n " + "Bad Id: " + strconv . Itoa ( id ) + " \n "
index := findCliche ( id )
if index > = 0 {
cliche := clichesList [ index ]
msg = " \n " + strconv . Itoa ( id ) + ": " + cliche . Cliche + " " + cliche . Counter + " \n "
}
return msg
}
// Create a new clichePair and add to list
func addPair ( cp * clichePair ) string {
cp . Id = masterId
masterId ++
clichesList = append ( clichesList , cp )
return " \n Created: " + cp . Cliche + " " + cp . Counter + " \n "
}
// Edit an existing clichePair
func editPair ( id int , cliche string , counter string ) string {
msg := " \n " + "Bad Id: " + strconv . Itoa ( id ) + " \n "
index := findCliche ( id )
if index > = 0 {
clichesList [ index ] . Cliche = cliche
clichesList [ index ] . Counter = counter
msg = " \n Cliche edited: " + cliche + " " + counter + " \n "
}
return msg
}
// Delete a clichePair
func deletePair ( id int ) string {
idStr := strconv . Itoa ( id )
msg := " \n " + "Bad Id: " + idStr + " \n "
index := findCliche ( id )
if index > = 0 {
clichesList = append ( clichesList [: index ], clichesList [ index + 1 :] ... )
msg = " \n Cliche " + idStr + " deleted \n "
}
return msg
}
//*** utility functions
func findCliche ( id int ) int {
for i := 0 ; i < len ( clichesList ); i ++ {
if id == clichesList [ i ] . Id {
return i ;
}
}
return - 1 // not found
}
func getIdFromRequest ( req * http. Request ) int {
vars := mux . Vars ( req )
id , _ := strconv . Atoi ( vars [ "id" ])
return id
}
func getDataFromRequest ( req * http. Request ) ( string , string ) {
// Extract the user-provided data for the new clichePair
req . ParseForm ()
form := req . Form
cliche := form [ "cliche" ][ 0 ] // 1st and only member of a list
counter := form [ "counter" ][ 0 ] // ditto
return cliche , counter
}
func logIt ( msg string ) {
fmt . Println ( msg )
}
func populateClichesList () {
var cliches = [] string {
"Out of sight, out of mind." ,
"A penny saved is a penny earned." ,
"He who hesitates is lost." ,
}
var counterCliches = [] string {
"Absence makes the heart grow fonder." ,
"Penny-wise and dollar-foolish." ,
"Look before you leap." ,
}
for i := 0 ; i < len ( cliches ); i ++ {
cp := new ( clichePair )
cp . Id = masterId
masterId ++
cp . Cliche = cliches [ i ]
cp . Counter = counterCliches [ i ]
clichesList = append ( clichesList , cp )
}
}
为了专注于请求路由和验证, crud应用程序不使用HTML页面作为对请求的响应。 相反,请求会产生纯文本响应消息:陈词条对列表是对GET请求的响应,确认新的陈词对已添加到列表中是对POST请求的响应,依此类推。 这种简化使得可以使用curl之类的命令行实用程序轻松测试应用程序,尤其是
gorilla/mux组件。
可以从GitHub安装gorilla/mux
软件包。 Crud应用程序无限期运行; 因此,应使用Control-C或等效控件将其终止。 可在我的网站上找到 crud应用程序的代码,以及自述文件和示例卷曲测试。
2.请求路由
mux.Router
扩展了REST样式的路由,它对HTTP方法(例如GET)和URL末尾的URI或路径(例如/ cliches )给予同等的权重。 URI用作HTTP动词(方法)的名词。 例如,在HTTP请求中,诸如
GET / cliches
意味着获得所有陈词滥调对 ,而诸如
POST / cliches
表示从HTTP正文中的数据创建一个词条对 。
在Crud Web应用程序中,有五个函数充当HTTP请求的五种变体的请求处理程序:
ClichesAll ( ... ) # GET : get all of the cliche pairs
ClichesOne ( ... ) # GET : get a specified cliche pair
ClichesCreate ( ... ) # POST : create a new cliche pair
ClichesEdit ( ... ) # PUT : edit an existing cliche pair
ClichesDelete ( ... ) # DELETE : delete a specified cliche pair
每个函数有两个参数:一个
http.ResponseWriter用于发送响应返回给请求者,并且一个指向http.Request
,它封装从底层HTTP请求信息。 gorilla/mux
软件包使向Web服务器注册这些请求处理程序以及执行基于正则表达式的验证变得容易。
Crud应用程序中的startServer
函数注册了请求处理程序。 考虑这对注册,将router
作为mux.Router
实例:
router . HandleFunc ( "/" , ClichesAll ) . Methods ( "GET" )
router . HandleFunc ( "/cliches" , ClichesAll ) . Methods ( "GET" )
这些语句意味着对单个斜杠/或/
ClichesAll
的GET请求应路由到ClichesAll
函数,然后由ClichesAll
函数处理该请求。 例如, curl请求(以%作为命令行提示符)
% curl -- request GET localhost : 8888 /
产生以下响应:
1 : Out of sight , out of mind . Absence makes the heart grow fonder .
2 : A penny saved is a penny earned . Penny - wise and dollar - foolish .
3 : He who hesitates is lost . Look before you leap .
这三个陈词滥调对是Crud应用程序中的初始数据。
在这对注册声明中
router . HandleFunc ( "/cliches" , ClichesAll ) . Methods ( "GET" )
router . HandleFunc ( "/cliches" , ClichesCreate ) . Methods ( "POST" )
URI相同( / cliches ),但动词不同:第一种情况下为GET,第二种情况下为POST。 该注册示例了REST风格的路由,因为仅动词之间的差异就足以将请求分派给两个不同的处理程序。
注册中允许使用多个HTTP方法,尽管这会束缚REST风格路由的精神:
router . HandleFunc ( "/cliches" , DoItAll ) . Methods ( "POST" , "GET" )
HTTP请求可以在动词和URI之外的功能上进行路由。 例如注册
router . HandleFunc ( "/cliches" , ClichesCreate ) . Schemes ( "https" ) . Methods ( "POST" )
要求HTTPS访问POST请求才能创建新的陈词滥调对。 以类似的方式,注册可能要求请求具有指定的HTTP标头元素(例如,身份验证凭据)。
3.要求验证
gorilla/mux
软件包采用一种简单直观的方法来通过正则表达式请求验证。 考虑此请求处理程序进行“ 获得一个”操作:
router . HandleFunc ( "/cliches/{id:[0-9]+}" , ClichesOne ) . Methods ( "GET" )
此注册排除了HTTP请求,例如
% curl -- request GET localhost : 8888 / cliches / foo
因为foo不是十进制数字。 该请求将产生熟悉的404(未找到)状态代码。 在此处理程序注册中包括正则表达式模式可确保仅当请求URI以十进制整数值结尾时,才调用ClichesOne
函数来处理请求:
% curl -- request GET localhost : 8888 / cliches / 3 # ok
再举一个例子,考虑一下请求
% curl -- request PUT -- data "..." localhost : 8888 / cliches
此请求导致状态代码为405(错误方法),因为/ cliches URI仅在crud应用程序中注册,用于GET和POST请求。 与GET一个请求一样,PUT请求必须在URI的末尾包含数字ID:
router . HandleFunc ( "/cliches/{id:[0-9]+}" , ClichesEdit ) . Methods ( "PUT" )
4.并发问题
gorilla/mux
路由器将对注册请求处理程序的每个调用作为单独的goroutine执行,这意味着并发已烘焙到程序包中。 例如,如果有十个同时请求,例如
% curl -- request POST -- data "..." localhost : 8888 / cliches
然后mux.Router
启动十个goroutine来执行ClichesCreate
处理程序。
在五个请求操作GET all,GET one,POST,PUT和DELETE中,最后三个更改请求的资源,即clichesList
陈词滥调对的共享clichesList
。 因此, crud应用程序需要通过协调对clichesList
访问来确保安全的并发性。 用不同但等效的术语, crud应用程序必须阻止clichesList
上的竞赛条件。 在生产环境中,可以使用数据库系统来存储诸如clichesList
类的资源,然后可以通过数据库事务来管理安全并发。
Crud应用程序采用推荐的Go方法来实现安全并发:
- 一旦Web服务器开始侦听请求,只有一个goroutine(在crud应用程序
startServer
函数中启动的资源管理器)就可以访问clichesList
。 - 诸如
ClichesCreate
和ClichesAll
类的请求处理程序将一个crudRequest
实例(指向)发送到Go通道(默认情况下是线程安全的),并且资源管理器仅从该通道读取。 然后,资源管理器在clichesList
上执行请求的操作。
安全并发体系结构可以概述如下:
crudRequest read/write
request handlers------------->resource manager------------>clichesList
使用这种架构,不需要显式锁定
clichesList ,因为一旦CRUD请求开始进入,只有一个goroutine,即资源管理器访问clichesList
。
为了使Crud应用程序尽可能保持并发,必须在一方面的请求处理程序与另一方面的单个资源管理器之间进行有效的分工。 此处供您参考,是ClichesCreate
请求处理程序:
func ClichesCreate ( res http . ResponseWriter , req * http. Request ) {
cliche , counter := getDataFromRequest ( req )
cp := new ( clichePair )
cp . Cliche = cliche
cp . Counter = counter
cr := &crudRequest { verb : POST , cp : cp , confirm : make ( chan string )}
completeRequest ( cr , res , "create" )
}
ClichesCreate
调用实用程序函数getDataFromRequest
,该函数从POST请求中提取新的陈词滥调和ClichesCreate
。 然后, ClichesCreate
函数创建一个新的ClichePair
,设置两个字段,并创建一个crudRequest
发送给单个资源管理器。 该请求包括一个确认通道,资源管理器使用该通道将信息返回给请求处理程序。 由于尚未访问clichesList
因此可以在不涉及资源管理器的情况下完成所有设置工作。
在ClichesCreate
函数和其他请求处理程序的末尾调用的completeRequest
实用程序函数
completeRequest ( cr , res , "create" ) // shown above
通过将crudRequest
放入crudRequests
通道,使资源管理器发挥作用:
func completeRequest ( cr * crudRequest , res http . ResponseWriter , logMsg string ) {
crudRequests< - cr // send request to resource manager
msg := <- cr . confirm // await confirmation string
res . Write ([] byte ( msg )) // send confirmation back to requester
logIt ( logMsg ) // print to the standard output
}
对于POST请求,资源管理器调用实用程序功能
addPair ,它会更改clichesList
资源:
func addPair ( cp * clichePair ) string {
cp . Id = masterId // assign a unique ID
masterId ++ // update the ID counter
clichesList = append ( clichesList , cp ) // update the list
return " \n Created: " + cp . Cliche + " " + cp . Counter + " \n "
}
资源管理器为其他CRUD操作调用类似的实用程序功能。 值得重复的是,一旦Web服务器开始接受请求,资源管理器是读取或写入
clichesList的唯一goroutine。
对于任何类型的Web应用程序, gorilla/mux
软件包都以直观,直观的API提供请求路由,请求验证和相关服务。 Crud Web应用程序突出显示了程序包的主要功能。 给包裹试驾,您很可能会成为买家。
翻译自: https://opensource.com/article/18/8/http-request-routing-validation-gorillamux
mux路由
mux路由_使用大猩猩/ mux进行HTTP请求路由和验证相关推荐
- ubuntu 删除路由_如何在Ubuntu Linux中删除路由?
ubuntu 删除路由 I have some route in my routing table. But I want to delete one route from routing table ...
- 胶囊路由_评论:胶囊之间的动态路由
胶囊路由 Link to paper: https://arxiv.org/pdf/1710.09829.pdf 链接到论文: https : //arxiv.org/pdf/1710.09829.p ...
- isis学不到looback口的路由_随手装了台LEDE软路由,测试WAN口能否跑万兆(上篇)...
称之为上篇,是因为最终的测试结果并没有符合自己的预期,只折腾了几个小时到深夜,不想在当前花太多时间用在这方面上,所以暂时中止了折腾,待时间宽松些继续找原因,甚至更换系统.主板.添加网卡等.搞一台软路由 ...
- ionic4中点击跳转路由_在Ionic 4中使用角度路由
ionic4中点击跳转路由 The Router module is one of the most important in the Angular library. Paired with Ion ...
- element label动态赋值_浅析 vuerouter 源码和动态路由权限分配
背景 上月立过一个 flag,看完 vue-router 的源码,可到后面逐渐发现 vue-router 的源码并不是像很多总结的文章那么容易理解,阅读过你就会发现里面的很多地方都会有多层的函数调用关 ...
- 华为防火墙做单臂路由_华为单臂路由配置实例
华为单臂路由实验配置(共8篇)华为 AR2200路由器单臂路由配置实例华为 AR2200路由器单臂路由配置实例作者:救世主220实验日期:2015 6 29实验拓扑如下:AR5配置:[AR5]dis ...
- 静态路由_【零基础学云计算】静态路由!静态路由!静态路由!原理与配置
本次和各位小伙伴分享的是静态路由的原理和配置,接下来我会从以下几个方面来和大家进行解析: 1.路由器的工作原理 2.路由表的形成 3.静态路由和默认路由 4.路由器转发数据包的封装过程 5.静态路由和 ...
- 三层交换机能传递路由吗?_华为ensp三层交换机VLAN配置静态路由互通
华为三层交换机静态路由与VLAN配置 目的:学会静态路由的原理与三层交换机vlan划分配置 图中PC1划分在VLAN2下与PC2划分在VLAN4下互通,配置如下: sys --进入系统命令 [huaw ...
- flask框架视图和路由_角度视图,路由和NgModule的解释
flask框架视图和路由 Angular vs AngularJS (Angular vs AngularJS) AngularJS (versions 1.x) is a JavaScript-ba ...
最新文章
- Nginx 使用中文URL,中文目录路径
- 消除 Xcode7 中 directory not found for option 'xxxx' 警告
- Apache 2.4配置反向代理
- linux内核函数open源码,open()在Linux内核的实现(1)-基本实现
- js打开、关闭页面和运行代码那些事
- Linux统一编程接口,restful接口设计规范总结
- 1.10 编程基础之简单排序_10 单词排序
- 自检代码中trustmanager漏洞_通达OA远程代码执行漏洞通告
- 高光谱图像结合机器学习方法无损检测猕猴桃
- 欧几里得算法及扩展欧几里得算法简单解释
- javascript flash 弹框
- Oracle 联合主键
- 【五分钟力扣】198题—用python3解决打家劫舍问题
- 纯技术上来说,《看门狗》里的各种骇客技术有可能实现吗?
- 【饭谈】为什么总有人劝你用mac来办公?
- 云栖大会 | Greenplum 6.0内核优化解读和7.0展望
- linux编程学习路线,秘辛:2019上半年程序员生存报告
- Python性能优化
- python遍历文件夹下文件 批量重命名
- Oracle 一致性读和当前读