go server框架学习之路 - 写一个自己的go框架
go server框架学习之路 - 写一个自己的go框架
- 用简单的代码实现一个go框架
- 代码地址: https://github.com/cw731/gcw
1 创建一个简单的框架
代码
package https
import "net/http"
// 创建自己的引擎
type Engine struct {
}
// 实现engine的ServeHTTP 有了这个方法 engine就属于一个http的handle了
func (e *Engine)ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("HTTP/1.0 200 OK\r\n" +
"\r\n" +
"你好中国"))
}
func Run() {
http.ListenAndServe(":8080",&Engine{})
}
测试代码和执行结果:
package main
import "gcw/pkg/https"
func main() {
https.Run()
}
****************************************
HTTP/1.0 200 OK
你好中国
2 封装请求和响应
代码
package https
import "net/http"
// 统一上下文 以后写自己的 视图函数就不用写一长串参数了
type Context struct {
Request *http.Request
Writer http.ResponseWriter
}
// 定义自己的HandlerFunc
type HandlerFunc func(*Context)
// 实现自己的HandlerFunc的ServeHTTP方法
func (f HandlerFunc) ServeHTTP(c *Context) {
f(c)
}
// 创建自己的引擎
type Engine struct {}
// 实现engine的ServeHTTP 有了这个方法 engine就属于一个http的handle了
func (e *Engine)ServeHTTP(w http.ResponseWriter, r *http.Request) {
c := &Context{
Request: r,
Writer: w,
}
testHandlerFunc(c)
}
func testHandlerFunc(c *Context) {
c.Writer.Write([]byte("测试2"))
}
func Run() {
//http.Handle("/", &Engine{})
http.ListenAndServe(":8080",&Engine{})
}
测试代码和执行结果:
测试代码同1
************************
测试2
3 实现路由功能
代码
package https
import "net/http"
// 统一上下文 以后写自己的 视图函数就不用写一长串参数了
type Context struct {
Request *http.Request
Writer http.ResponseWriter
index int8 // 配合next 执行handlers
handlers []HandlerFunc //
}
// 执行下一个handle
func (c *Context) Next() {
c.index++
for c.index < int8(len(c.handlers)) {
c.handlers[c.index](c)
c.index++
}
}
// 定义自己的HandlerFunc
type HandlerFunc func(*Context)
// 实现自己的HandlerFunc的ServeHTTP方法
func (f HandlerFunc) ServeHTTP(c *Context) {
f(c)
}
// 路由
type Router struct {
method string
root string
handles []HandlerFunc
}
// 往engine 的 routers 中添加路由
func (e *Engine)AddRouter(method string, path string , h []HandlerFunc) {
e.routers[method+"_"+path] = &Router{
method: method,
root: path,
handles: h,
}
}
func (e *Engine)Get(path string, h ...HandlerFunc) {
e.AddRouter("GET", path, h)
}
func (e *Engine)POST(path string, h ...HandlerFunc) {
e.AddRouter("POST", path, h)
}
// 创建自己的引擎
type Engine struct {
routers map[string]*Router
}
// 通过new 创建engine 初始化参数
func New() *Engine{
return &Engine{routers:make(map[string]*Router)}
}
// 实现engine的ServeHTTP 有了这个方法 engine就属于一个http的handle了
func (e *Engine)ServeHTTP(w http.ResponseWriter, r *http.Request) {
method := r.Method
path := r.RequestURI
//remoteAddr := r.RemoteAddr
router := e.routers[method+"_"+path]
c := &Context{
Request: r,
Writer: w,
index: -1,
handlers: router.handles,
}
c.Next()
}
func (e *Engine)Run() {
//http.Handle("/", &Engine{})
http.ListenAndServe(":8080",e)
}
测试代码和执行结果:
package main
import "gcw/pkg/https"
func main() {
app := https.New()
app.Get("/hello", testHandlerFunc)
app.Run()
}
func testHandlerFunc(c *https.Context) {
c.Writer.Write([]byte("测试3"))
}
4 完善路由404
代码
// 实现engine的ServeHTTP 有了这个方法 engine就属于一个http的handle了
func (e *Engine)ServeHTTP(w http.ResponseWriter, r *http.Request) {
method := r.Method
path := r.RequestURI
//remoteAddr := r.RemoteAddr
router := e.routers[method+"_"+path]
if router == nil {
w.Write([]byte("404 你访问的页面不存在"))
return
}
c := &Context{
Request: r,
Writer: w,
index: -1,
handlers: router.handles,
}
c.Next()
}
测试代码和执行结果:
404 你访问的页面不存在
5 日志打印功能
新建logger.go
package https
import (
"fmt"
"path"
"runtime"
"time"
)
type loggerMessage struct {
Millisecond int64 `json:"timestamp"`
MillisecondFormat string `json:"time_format"`
LevelString string `json:"level_string"`
Body string `json:"body"`
Position string `json:"position"`
}
type Logger struct {
}
func (logger *Logger) Writer(level string, msg string){
funcName := "null"
pc, file, line, ok := runtime.Caller(2)
if !ok {
file = "null"
line = 0
} else {
funcName = runtime.FuncForPC(pc).Name()
}
_, filename := path.Split(file)
loggerMsg := &loggerMessage{
Millisecond: time.Now().UnixNano() / 1e6,
MillisecondFormat: time.Now().Format("2006-01-02 15:04:05.999"),
LevelString: level,
Body: msg,
Position: fmt.Sprintf("%s %d %s", filename, line, funcName),
}
logger.OutPut(loggerMsg)
}
func (logger *Logger)OutPut(msg *loggerMessage) {
fmt.Println(msg)
}
func (logger *Logger)Info(msg string) {
logger.Writer("info", msg)
}
engine 和 new中添加初始化log
func New() *Engine{
return &Engine{
routers:make(map[string]*Router),
log:Logger{},
}
}
type Engine struct {
routers map[string]*Router
log Logger
}
使用 及效果
tts = time.Now().UnixNano() - tts
e.log.Info(fmt.Sprintf("%s %s %s %3.6fs",remoteAddr, method, path, float64(float64(tts)/1e9)))
func (e *Engine)Run() {
//http.Handle("/", &Engine{})
e.log.Info("服务器启动: 127.0.0.1:8080")
http.ListenAndServe(":8080",e)
}
***************************************
&{1586071294752 2020-04-05 15:21:34.752 info 服务器启动: 127.0.0.1:8080 server.go 79 gcw/pkg/https.(*Engine).Run}
&{1586071298492 2020-04-05 15:21:38.492 info 127.0.0.1:54446 GET /hello 0.000000s server.go 66 gcw/pkg/https.(*Engine).ServeHTTP}
go server框架学习之路 - 写一个自己的go框架的更多相关文章
- 郑晔谈 Moco 框架的开发:写一个好的内部 DSL ,写一个表达性好的程序
作者:张龙 出处:http://www.infoq.com/cn/news/2013/07/zhengye-on-moco 郑晔谈Moco框架的开发:写一个好的内部DSL,写一个表达性好的程序 作者 ...
- 用Python写一个简单的Web框架
一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...
- 【SpringCloud之pigx框架学习之路 】1.基础环境安装
[SpringCloud之pigx框架学习之路 ]1.基础环境安装 [SpringCloud之pigx框架学习之路 ]2.部署环境 1.Cmder.exe安装 (1) windows常用命令行工具 下 ...
- 【SpringCloud之pigx框架学习之路 】2.部署环境
[SpringCloud之pigx框架学习之路 ]1.基础环境安装 [SpringCloud之pigx框架学习之路 ]2.部署环境 1.下载代码 git clone https://git.pig4c ...
- 自己的Scrapy框架学习之路
开始自己的Scrapy 框架学习之路. 一.Scrapy安装介绍 参考网上资料,先进行安装 使用pip来安装Scrapy 在开始菜单打开cmd命令行窗口执行如下命令即可 pip install Scr ...
- Summer——从头开始写一个简易的Spring框架
Summer--从头开始写一个简易的Spring框架 参考Spring框架实现一个简易类似的Java框架.计划陆续实现IOC.AOP.以及数据访问模块和事务控制模块. ...
- 动手写一个简单的Web框架(模板渲染)
动手写一个简单的Web框架(模板渲染) 在百度上搜索jinja2,显示的大部分内容都是jinja2的渲染语法,这个不是Web框架需要做的事,最终,居然在Werkzeug的官方文档里找到模板渲染的代码. ...
- 动手写一个简单的Web框架(Werkzeug路由问题)
动手写一个简单的Web框架(Werkzeug路由问题) 继承上一篇博客,实现了HelloWorld,但是这并不是一个Web框架,只是自己手写的一个程序,别人是无法通过自己定义路由和返回文本,来使用的, ...
- 动手写一个简单的Web框架(HelloWorld的实现)
动手写一个简单的Web框架(HelloWorld的实现) 关于python的wsgi问题可以看这篇博客 我就不具体阐述了,简单来说,wsgi标准需要我们提供一个可以被调用的python程序,可以实函数 ...
随机推荐
- Java面试必问之Hashmap底层实现原理(JDK1.8)
1. 前言 上一篇从源码方面了解了JDK1.7中Hashmap的实现原理,可以看到其源码相对还是比较简单的.本篇笔者和大家一起学习下JDK1.8下Hashmap的实现.JDK1.8中对Hashmap做 ...
- sql01
1.简介 2.外键 1)主键: 3.表间关联与外键 上面的两个表格通过厂家编号联系在一起,彼此相对独立.厂家编号就称为外键.厂家编号是厂家表的主键. 4.SQL 1)数据库登录 服务器名称选择:①机器 ...
- 使用webpack从0搭建多入口网站脚手架,可复用导航栏/底部通栏/侧边栏,根据页面文件自动更改配置,支持ES6/Less
之前只知道webpack很强大,但是一直没有深入学习过,这次从头看了一下教程,然后从0开始搭建了一个多入口网站的开发脚手架,期间遇到过很多问题,所以有心整理一下,希望能给大家一点帮助. 多HTML网站 ...
- css实现边框动画效果
最近写了几个页面都用到css动画,以及很多before,after伪类.在此记录一下成果.css边框循环动画,页面效果如下: 1.沿着边框动画的图形使用before,after伪类写的.当时想用切图来 ...
- vmware企业虚拟化平台vSphere管理与配置
├─1-CCIE-DC课程介绍.avi ├─2-vSphere-简介.avi ├─3-vSphere-新功能介绍.avi ├─4-vSphere-授权介绍.avi ├─5-vSphere-课程拓扑介绍 ...
- Keil MDK版兼容51系列单片机开发环境安装
一.安装源文件下载 百度网盘链接:https://pan.baidu.com/s/18tnjFgVat4q2hDSh7LAD8A 提取码: 2295 二.安装及破解 1.安装51的编辑器 双击安 ...
- Head First设计模式——蝇量和解释器模式
蝇量 蝇量模式:如果让某个类的一个实例能用来提供许多“虚拟实例”,就使用蝇量模式. 在一个设计房子的平台中,周围要加上一些树,树有一个坐标XY坐标位置,而且可以根据树的年龄动态将自己绘制出来.如果我们 ...
- [转载]Linux服务器丢包故障的解决思路及引申的TCP/IP协议栈理论
Linux服务器丢包故障的解决思路及引申的TCP/IP协议栈理论 转载至:https://www.sdnlab.com/17530.html 我们使用Linux作为服务器操作系统时,为了达到高并发处理 ...
- vquery 一些应用
// JavaScript Document function myAddEvent(obj,sEv,fn){ if(obj.attachEvent){ obj.attachEvent('on'+sE ...
- 分享几个 PHP 编码的最佳实践
对于初学者而言,可能很难理解为什么某些做法更安全. 但是,以下一些技巧可能超出了 PHP 的范围. 始终使用大括号 让我们看下面的代码: if (isset($condition) && ...