golang利用不到20行代码实现路由调度详解

前言

本文主要介绍了关于golang实现路由调度的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧

项目地址

github (本地下载)

本项目依赖

使用标准库实现,无额外依赖

为什么需要路由调度层

golang http标准库只能精确匹配请求的URI,然后执行handler。现在一般web项目都至少有个Controller层,以struct实现,根据不同的请求路径派发到不同的方法中去。

路由调度器定义

由于golang暂时还不可以动态创建对象(比如java的Class.forName("xxx").newInstance(),xxx是任意存在的class名称)。所以需要手动注册一下controller关系。

  1. 定义routes保存controller指针
  2. 解析请求过来的URL查询参数,暂定a为action名称,c为controller名称,本文偷了下懒,没对PATH_INFO做处理,也没有对actionName的首字母自动大写,这个不影响本文要传达的核心内容,有兴趣的读者可以自行实现。
  3. 根据URL中的controllerName找到对应的controller
  4. 使用反射将当前请求对象的*http.Request和http.ResponseWriter设置到该Controller
  5. 使用反射以及actionName对应该controller的方法

由于golang的继承不是一般的OOP,所以也没有父子类这种说法,路由注册那里只能使用interface{}

代码实现

app/app.go

该文件为核心调度文件

package app

import (
 "net/http"
 "reflect"
 "fmt"
)

type application struct {
 routes map[string]interface{}
}

func New() *application {
 return &application{
  routes: make(map[string]interface{}),
 }
}

func (p *application) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 controllerName := r.URL.Query().Get("c")
 actionName := r.URL.Query().Get("a")
 if controllerName == "" || actionName == "" {
  http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
  return
 }
 route, ok := p.routes[controllerName]
 if !ok {
  http.Error(w, "Controller Not Found", http.StatusNotFound)
  return
 }
 ele := reflect.ValueOf(route).Elem()
 ele.FieldByName("Request").Set(reflect.ValueOf(r))
 ele.FieldByName("Response").Set(reflect.ValueOf(w))
 ele.MethodByName(actionName).Call([]reflect.Value{})
}

func (p *application) printRoutes() {
 for route, controller := range p.routes {
  ele := reflect.ValueOf(controller).Type().String()
  fmt.Printf("%s %s\n", route, ele)
 }
}

func (p *application) Get(route string, controller interface{}) {
 p.routes[route] = controller
}

func (p *application) Run(addr string) error {
 p.printRoutes()
 fmt.Printf("listen on %s\n", addr)
 return http.ListenAndServe(addr, p)
}

app/controller.go

控制器"基类"

package app

import "net/http"

type Controller struct {
 Response http.ResponseWriter
 Request *http.Request
}

controller/site.go

具体业务逻辑类

package controllers

import (
 "fmt"
 "app"
)

type SiteController struct {
 app.Controller
}

func (p SiteController) Index() {
 fmt.Fprint(p.Response, p.Request.RequestURI)
}

main.go

入口文件

package main

import (
 _ "github.com/go-sql-driver/mysql"
 "app"
 "controllers"
)

func main() {
 application := app.New()
 application.Get("site", &controllers.SiteController{})
 application.Run(":8080")
}

运行项目

启动进程

访问http://localhost:8080?c=site&a=Index会输出/?c=site&a=Index

写在最后

希望这个小小的项目能启发到各位读者,早日开发出适合自己的Web框架!

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • golang中命令行库cobra的使用方法示例

    简介 Cobra既是一个用来创建强大的现代CLI命令行的golang库,也是一个生成程序应用和命令行文件的程序.下面是Cobra使用的一个演示: Cobra提供的功能 简易的子命令行模式,如 app server, app fetch等等 完全兼容posix命令行模式 嵌套子命令subcommand 支持全局,局部,串联flags 使用Cobra很容易的生成应用程序和命令,使用cobra create appname和cobra add cmdname 如果命令输入错误,将提供智能建议,如 ap

  • golang sql连接池的实现方法详解

    前言 golang的"database/sql"是操作数据库时常用的包,这个包定义了一些sql操作的接口,具体的实现还需要不同数据库的实现,mysql比较优秀的一个驱动是:github.com/go-sql-driver/mysql,在接口.驱动的设计上"database/sql"的实现非常优秀,对于类似设计有很多值得我们借鉴的地方,比如beego框架cache的实现模式就是借鉴了这个包的实现:"database/sql"除了定义接口外还有一个重

  • Golang中定时器的陷阱详解

    前言 在业务中,我们经常需要基于定时任务来触发来实现各种功能.比如TTL会话管理.锁.定时任务(闹钟)或更复杂的状态切换等等.百纳网主要给大家介绍了关于Golang定时器陷阱的相关内容,所谓陷阱,就是它不是你认为的那样,这种认知误差可能让你的软件留下隐藏Bug.刚好Timer就有3个陷阱,我们会讲 1)Reset的陷阱和 2)通道的陷阱, 3)Stop的陷阱与Reset的陷阱类似,自己探索吧. 下面话不多说了,来一起看看详细的介绍吧 Reset的陷阱在哪 Timer.Reset()函数的返回值是

  • golang设置http response响应头与填坑记录

    1. 设置WriteHeader的顺序问题 之前遇到个问题,在一段代码中这样设置WriteHeader,最后在header中取Name时怎么也取不到. w.WriteHeader(201) w.Header().Set("Name", "my name is smallsoup") 用 golang 写 http server 时,可以很方便可通过 w.Header.Set(k, v) 来设置 http response 中 header 的内容.但是需要特别注意的

  • golang flag简单用法

    通过一个简单的实例,来让大家了解一下golang flag包的一个简单的用法 package main import ( "flag" "strings" "os" "fmt" ) var ARGS string func main() { var uptime *bool = new(bool) flag.BoolVar(uptime,"u", false, "print system upti

  • Golang如何交叉编译各个平台的二进制文件详解

    Golang交叉编译平台的二进制文件 熟悉golang的人都知道,golang交叉编译很简单的,只要设置几个环境变量就可以了 # mac上编译linux和windows二进制 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build # linux上编译mac和windows二进制 CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go

  • 详解Golang实现http重定向https的方式

    以前写代码时,都是直接将程序绑定到唯一端口提供http/https服务,在外层通过反向代理(nginx/caddy)来实现http和https的切换.随着上线后的服务越来越多,有一些服务无法直接通过反向代理来提供这种重定向,只能依靠代码自己实现.所以简要记录一下如何在代码中实现http到https的重定向. 分析 无论是反向代理还是代码自己实现,问题的本质都是判断请求是否是https请求. 如果是则直接处理,如果不是,则修改请求中的url地址,同时返回客户端一个重定向状态码(301/302/30

  • 详解如何热重启golang服务器

    服务端代码经常需要升级,对于线上系统的升级常用的做法是,通过前端的负载均衡(如nginx)来保证升级时至少有一个服务可用,依次(灰度)升级. 而另一种更方便的方法是在应用上做热重启,直接升级应用而不停服务. 原理 热重启的原理非常简单,但是涉及到一些系统调用以及父子进程之间文件句柄的传递等等细节比较多. 处理过程分为以下几个步骤: 监听信号(USR2) 收到信号时fork子进程(使用相同的启动命令),将服务监听的socket文件描述符传递给子进程 子进程监听父进程的socket,这个时候父进程和

  • golang利用不到20行代码实现路由调度详解

    前言 本文主要介绍了关于golang实现路由调度的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧 项目地址 github (本地下载) 本项目依赖 使用标准库实现,无额外依赖 为什么需要路由调度层 golang http标准库只能精确匹配请求的URI,然后执行handler.现在一般web项目都至少有个Controller层,以struct实现,根据不同的请求路径派发到不同的方法中去. 路由调度器定义 由于golang暂时还不可以动态创建对象(比如java的Class.

  • Golang并发编程之main goroutine的创建与调度详解

    目录 0. 简介 1. 创建main goroutine 2. 调度main goroutine 0. 简介 上一篇博客我们分析了调度器的初始化,这篇博客我们正式进入main函数及为其创建的goroutine的过程分析. 1. 创建main goroutine 接上文,在runtime/asm_amd64.s文件的runtime·rt0_go中,在执行完runtime.schedinit函数进行调度器的初始化后,就开始创建main goroutine了. // create a new goro

  • python随机生成大小写字母数字混合密码(仅20行代码)

    用简单的方法生成随机性较大的密码 仅用20行代码随机生成密码 核心思路:利用random模块 random模块随机生成数字,大小写字母,循环次数 while循环+随机生成的循环次数-->随机plus++ 大写字母ASKII码在65-90之间 小写字母Askll码在97-122之间 最终效果: x个大写字母+y个数字+z个小写字母(x,y,z均随机) 随机性相较于以往单调的 小写+数字+大写+小写+数字+大写- 循环有所提升 import random print("随机数生成") time

  • PHP基于关联数组20行代码搞定约瑟夫问题示例

    本文实例讲述了PHP基于关联数组20行代码搞定约瑟夫问题.分享给大家供大家参考,具体如下: 记得前段时间一写做java开发的兄弟对我说他java60行做了个约瑟夫问题,挺不错的.调侃php应该写这个挺不行的. 于是 呵呵... 洋洋洒洒 20行,写完自己都有些不相信了.哈哈 让不了解php的见识哈php的快捷轻便之处. ps:其实个人挺反感用代码行数来衡量代码数量的,感觉常把代码行数挂嘴边的大多无奈装2.此文仅属闲余娱乐. 回顾一下约瑟夫问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最

  • 不到20行代码用Python做一个智能聊天机器人

    伴随着自然语言技术和机器学习技术的发展,越来越多的有意思的自然语言小项目呈现在大家的眼前,聊天机器人就是其中最典型的应用,今天小编就带领大家用不到20行代码,运用两种方式搭建属于自己的聊天机器人. 1.神器wxpy库 首先,小编先向大家介绍一下本次运用到的python库,本次项目主要运用到的库有wxpy和chatterbot. wxpy是在 itchat库 的基础上,通过大量接口优化,让模块变得简单易用,并进行了功能上的扩展.什么是接口优化呢,简单来说就是用户直接调用函数,并输入几个参数,就可以

  • Python使用20行代码实现微信聊天机器人

    近来,打开微信群发消息,就会秒收到一些活跃分子的回复,有的时候感觉对方回答很在理,但是有的时候发现对方的回答其实是驴唇不对马嘴,仔细深究发现,原来对方是机器人.今天,小编就带大家用20行代码,带你一起打造一个微信聊天机器人,让你的微信群一直嗨不停~~ 首先我们需要安装一个微信相关的第三方库,itchat,在Windows上通过命令:pip install itchat,就可以将其安装. 其二,我们需要去图灵机器人官网:http://www.tuling123.com,注册一下,即可获得一个机器人

  • 20行代码教你用python给证件照换底色的方法示例

    1.图片来源 该图片来源于百度图片,如果侵权,请联系我删除!图片仅用于知识交流. 2.读取图片并显示 imread():读取图片: imshow():展示图片: waitkey():设置窗口等待,如果不设置,窗口会一闪而过: import cv2 import numpy as np # 读取照片 img=cv2.imread('girl.jpg') # 显示图像 cv2.imshow('img',img) # 窗口等待的命令,0表示无限等待 cv2.waitKey(0) 效果如下: 3.图片缩

  • Java用20行代码实现抖音小视频批量转换为gif动态图

    本文主要介绍了Java用20行代码实现抖音小视频批量转换为gif动态图,分享给大家,具体如下: 效果图 本功能实现需要用到第三方jar包 jave,JAVE 是java调用FFmpeg的封装工具. spring boot项目pom文件中添加以下依赖 <!-- https://mvnrepository.com/artifact/ws.schild/jave-core --> <dependency> <groupId>ws.schild</groupId>

  • 女神相册密码忘记了 我只用Python写了20行代码

    视频地址 我用20行代码,帮女神破解相册密码 一.事情是这样的 今早上班,公司女神小姐姐说,她去年去三亚旅游的照片打不开了 好奇问了一下才知道. 原来是,她把照片压缩了,而且还加了密码. 但是密码不记得了,只记得是一串6位数字. 话说照片压缩率也不高,而且还加密,难道是有什么可爱的小照片 但是作为一个正(ba)直(gua)的技术人员 我跟她说:"这事交给我,python写个脚本,帮你破解掉~~" 二.首先回顾一下女神的操作流程 对相册进行压缩的时候,添加了密码. LIke This ↓

  • Python用20行代码实现完整邮件功能

    目录 Python实现完整邮件 一.邮箱端设置 1.首先登录网页版126邮箱 2.打开 设置-POP3/SMTP/IMAP配置界面 3.新增一个授权码 二.python发送邮件 1.安装邮件模块 2.调用模块 3.设置邮件内容 4.添加附件 三.python读取邮件 Python实现完整邮件 先上效果: 一.邮箱端设置 首先,要对邮件进行一下设置,在邮箱端获取一个授权码. 1.首先登录网页版126邮箱 2.打开 设置-POP3/SMTP/IMAP配置界面 3.新增一个授权码 二.python发送

随机推荐