Golang个人web框架开发-学习流程

这篇具有很好参考价值的文章主要介绍了Golang个人web框架开发-学习流程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

github仓库

github地址:ameamezhou/golang-web-frame
后续还将继续学习更新

创建github仓库

Golang个人web框架开发-学习流程,golang,学习,后端,web框架开发,保姆教程,持续更新
设置免密登录
Golang个人web框架开发-学习流程,golang,学习,后端,web框架开发,保姆教程,持续更新
ssh-keygen 一路回车就OK 上面有告诉你密钥生成地址
Golang个人web框架开发-学习流程,golang,学习,后端,web框架开发,保姆教程,持续更新
红框为需要上传的公钥
Golang个人web框架开发-学习流程,golang,学习,后端,web框架开发,保姆教程,持续更新

web框架学习

首先明确目标–我们学习开发web框架的目的是

在日常的web开发中,我们经常要使用到web框架,python就有很多好用的框架,比如flaskdjango,前者小巧精美,后者厚重却有着齐全的功能,不同开发者在设计框架的时候会有他们不同的看法和理念,因此在不同框架之间就会有许多不同的区别。这对于Go语言来说也是一样的,我们看到有很多好用的框架,例如BeegoGin等等。但是我们在用这些框架的时候,我们可能需要去思考一下,其实这些框架翻找源码到底其实都是http等基础库构成的,但是我们为什么要使用它们呢?我们用框架究竟目的是什么?只有我们想明白了这一点我们才能更好的去做我们的开发工作,因此我决定做一个简单的框架实现这些基础功能。

开发周期

第一阶段–了解

package main

import (
	"net/http"
)

func main()  {
	http.HandleFunc("/", sayHello)
	http.ListenAndServe("localhost:9999", nil)
}


// 最基础的功能展示, 这里函数携带的参数是根据http库里面定义的
func sayHello(w http.ResponseWriter, r *http.Request){
	w.Write([]byte("hello world"))
}

实现一个最简单的web功能,就是打开页面输出 hello world 这里其实可以看到所需代码量其实和用现存的 gin 或者 beego 框架差不多,这里也能看出一些web框架大概的逻辑

然后我们在里面加点功能,增加点json输出

package main

import (
	"encoding/json"
	"net/http"
)

func main()  {
	http.HandleFunc("/", sayHello)
	http.ListenAndServe("localhost:9999", nil)
}


// 最基础的功能展示, 这里函数携带的参数是根据http库里面定义的
func sayHello(w http.ResponseWriter, r *http.Request){
	// 在页面输出展示json
	obj := make(map[string]interface{}, 0)
	obj["username"] = "xiawuyue"
	obj["password"] = "xiaoqizhou"

	// 这里是设置response 的响应头
	w.Header().Set("Content-Type", "application/json")
	// 这里是设置响应头的状态码  ok 就是 200
	w.WriteHeader(http.StatusOK)

	encoder := json.NewEncoder(w)

	if err := encoder.Encode(obj); err != nil {
		http.Error(w, err.Error(), 500)
	}

	w.Write([]byte("hello world"))
}

然后我们可以看到页面
Golang个人web框架开发-学习流程,golang,学习,后端,web框架开发,保姆教程,持续更新
还是非常有意思的

第一阶段思考

两个问题
1 这个demo和你常用的框架的区别
2 你觉得这个地方的重点在哪里

附加:
关于web框架 我们都用过flask框架 请问这些框架最底层的运行逻辑是如何?go实现框架的逻辑相比于python如何?
(欢迎评论讨论)

小结

其实这一阶段我们要着重关注http的路由

package main

import (
	"net/http"
)

func main()  {
	http.HandleFunc("/", sayHello)
	http.ListenAndServe("localhost:9999", nil)
}


// 最基础的功能展示, 这里函数携带的参数是根据http库里面定义的
func sayHello(w http.ResponseWriter, r *http.Request){
	w.Write([]byte("hello world"))
}

在这里我们可以看到http.ListenAndServe 这里我们传进去的是一个nil,在里面是需要绑定路由的,也就是我们最关键的地方在HandleFunc这里,我们可以看到路由分发是通过 http.HandleFunc(“路径”, 处理函数) 这种形式实现的

// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}

// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	if handler == nil {
		panic("http: nil handler")
	}
	mux.Handle(pattern, HandlerFunc(handler))
}

在ListenAndServe 这个函数中,我们第二个参数为nil,go会为我们分配一个默认的路由,会携带自己的路由结构体 ServeMux

// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
	server := &Server{Addr: addr, Handler: handler}
	return server.ListenAndServe()
}

// ServeMux还负责清除URL请求路径和主机标头,剥离端口号并重定向包含的任何请求。
// 或元素或重复的斜杠转换为等效的、更干净的URL。
type ServeMux struct {
	mu    sync.RWMutex // 这是一个互斥锁,保证并发
	m     map[string]muxEntry // 具体的路由规则
	es    []muxEntry // slice of entries sorted from longest to shortest.
	hosts bool       // whether any patterns contain hostnames 查看是否包含具体的host信息
}

其中我们最需要关注的就是这个m,我们注意到它是一个map类型,是一个 string 对应一个 muxEntry 结构体,这里最重要的就是muxEntry
Handler 其实就是一个interface接口,所以我们每一个HandFunc里面对应函数的类型都是要和这个 ServeHTTP(ResponseWriter, *Request) 保持一致的

type muxEntry struct {
	h       Handler // 具体路由对应的 handler
	pattern string  // 匹配字符串
}

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

题外话,go和python c 等语言不一样,这一块不需要通过sokcet来搞端口监听,http一个包就囊括了这些功能,所以我们可以深挖一下源码,看看究竟是怎么做得这方面的功能

第二阶段

看了上面的源码,我们实现的关键其实就是两个,一个是 ServeMux 一个是 muxEntry ,然后具体的 Handler 其实对应的就是一个ServeHTTP,我们需要实现的具体功能就是在这一块。所以其实我们完全可以自己来实现一个,不依赖 net/http 库它内置的一些功能,用我们自己的方式写一个 ServeHTTP

我们先梳理下这次的主要思路:

  • base1的重点就是简单了解http库
  • 我们来尝试自己写一个handle
  • 以后我们的所有的框架代码都不再放在main.go 下面 养成包开发的习惯从主函数去调用

根据第一阶段的总结,我们不难发现我们要是想要自己实现一个框架,那么核心就是要实现一个 muxEntryHandler
根据需求我们可以实现:

package xiawuyue

import (
	"fmt"
	"net/http"
)

/*
本地包用法:
require xiawuyue v0.0.0

replace xiawuyue => ./base2/xiawuyue
*/

type XiaWuYue struct {
	router map[string]HandleFunc
}

// New 直接调用New方法构建对象
func New() *XiaWuYue {
	return &XiaWuYue{ router: make(map[string]HandleFunc) }
}

// HandleFunc 简单定义一类函数  这就是后续具体的处理方法的类型
type HandleFunc func(w http.ResponseWriter, req *http.Request)

func (x *XiaWuYue)addRoute(method string, pattern string, handleFunc HandleFunc) {
	// 其中method 是用来区分 get post 等方法的
	// patter 是提到的 muxEntry 中的匹配字符串 也就是具体的路径
	key := method + "-" + pattern
	x.router[key] = handleFunc
}

func (x *XiaWuYue) Get(pattern string, handleFunc HandleFunc) {
	x.addRoute("GET", pattern, handleFunc)
}

func (x *XiaWuYue) Post(pattern string, handleFunc HandleFunc) {
	x.addRoute("POST", pattern, handleFunc)
}

func (x *XiaWuYue) Pull(pattern string, handleFunc HandleFunc) {
	x.addRoute("PULL", pattern, handleFunc)
}

func (x *XiaWuYue) Delete(pattern string, handleFunc HandleFunc) {
	x.addRoute("DELETE", pattern, handleFunc)
}

func (x *XiaWuYue) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	switch req.URL.Path {
	case "/":
		fmt.Println("你访问的是根路径")
		w.Write([]byte("hello world"))
		// 这里会导致只在终端打印  所以要修改逻辑
	}

	key := req.Method + "-" + req.URL.Path
	if handler, ok := x.router[key]; ok {
		handler(w, req)
	}
	
}

这里Handler其实就是要求一个接口,这个接口它必须有 ServerHTTP 这个功能就ok,只要能理解这个,做这个逻辑的时候就会很清晰了,我们要实现的就是它的基本功能,并通过 ServerHTTP 对找到的路由提供相应的服务就行,所以这里我们新生成的 struct xiawuyue 它就需要带有这个功能接口

好的 代码看到这里我们来回忆一下第一天的内容:

package main

import (
	"net/http"
)

func main()  {
	http.HandleFunc("/", sayHello)
	http.ListenAndServe("localhost:9999", nil)
}


// 最基础的功能展示, 这里函数携带的参数是根据http库里面定义的
func sayHello(w http.ResponseWriter, r *http.Request){
	w.Write([]byte("hello world"))
}

这里我们看到原始的 HandleFunc 我们并没有初始化任何一个struct 对象,并且在 ListenAndServe 这里传进去的也是个 nil , 这里的逻辑究竟是怎样的,我们为什么这样也能够去正常跑一个服务?

// serverHandler delegates to either the server's Handler or
// DefaultServeMux and also handles "OPTIONS *" requests.
type serverHandler struct {
	srv *Server
}

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
	handler := sh.srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
	if req.RequestURI == "*" && req.Method == "OPTIONS" {
		handler = globalOptionsHandler{}
	}

	if req.URL != nil && strings.Contains(req.URL.RawQuery, ";") {
		var allowQuerySemicolonsInUse int32
		req = req.WithContext(context.WithValue(req.Context(), silenceSemWarnContextKey, func() {
			atomic.StoreInt32(&allowQuerySemicolonsInUse, 1)
		}))
		defer func() {
			if atomic.LoadInt32(&allowQuerySemicolonsInUse) == 0 {
				sh.srv.logf("http: URL query contains semicolon, which is no longer a supported separator; parts of the query may be stripped when parsed; see golang.org/issue/25192")
			}
		}()
	}

	handler.ServeHTTP(rw, req)
}

我们可以在 http 包的server.go 中找到这样一段,这里其实很好理解,当 svrhandlernil 的时候,我们就会将 DefaultServeMux 导入当作这个 muxEntry ,它拥有 ServerHTTP 这个接口 可以实现相应的功能。

在我们都理解了这一块的知识之后,就写个总的 main.go 函数进行调用就ok文章来源地址https://www.toymoban.com/news/detail-803979.html

package main

import (
	"fmt"
	"net/http"
	"xiawuyue/base2/xiawuyue"
)

// base1的重点就是简单了解http库
// 我们来尝试自己写一个handle

// 以后我们的所有的框架代码都不再放在main.go 下面  养成包开发的习惯
// 从主函数去调用

//func main(){
//	http.ListenAndServe(":9999", new(xiawuyue.XiaWuYue))
//}

func main()  {
	//如果没有 New 方法
	//r := new(xiawuyue.XiaWuYue)
	r := xiawuyue.New()
	r.Get("/get", func(w http.ResponseWriter, req *http.Request) {
		fmt.Println("hello world")
		w.Write([]byte("hello world get"))
		// 这里println 只会在终端输出  所以我们后续还是要包装一个w.return 的功能,其实很简单
	})
	// 请大家给斗鱼9999fg投一票 球球了
	http.ListenAndServe("localhost:9999", r)
	// 到这一步完成了然后就去启动
}

第三阶段

到了这里,关于Golang个人web框架开发-学习流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Iris微服务框架_golang web框架_完整示例Demo

    Iris简介 Iris是一款Go语言中用来开发web应用的框架,该框架支持编写一次并在任何地方以最小的机器功率运行,如Android、ios、Linux和Windows等。该框架只需要一个可执行的服务就可以在平台上运行了。 Iris框架以简单而强大的api而被开发者所熟悉。iris除了为开发者提供非常简单

    2024年01月19日
    浏览(38)
  • 使用Golang实现一套流程可配置,适用于广告、推荐系统的业务性框架——简单应用

    在诸如广告、推荐等系统中,我们往往会涉及过滤、召回和排序等过程。随着系统业务变得复杂,代码的耦合和交错会让项目跌入难以维护的深渊。于是模块化设计是复杂系统的必备基础。这篇文章介绍的业务框架脱胎于线上多人协作开发、高并发的竞价广告系统,在实践中

    2024年02月14日
    浏览(44)
  • Golang Web3钱包开发指南

    以太坊(Ethereum)是目前最受欢迎的区块链平台之一,它提供了智能合约功能和去中心化应用(DApps)的开发能力。在以太坊生态系统中,Web3钱包扮演着关键角色,允许用户管理账户和密钥、发送交易、签名消息等操作。在本文中,我们将使用Golang和Web3库来开发一个基本的以

    2024年02月08日
    浏览(40)
  • golang web学习随便记4

    我们来开始学习如何存储数据。书中有一点不错,就是并不是一上来就告诉你存储数据使用数据库,因为不同的数据存储适合不同的手段。 先来看在内存中存储数据:下面的例子用结构体方式在内存存放数据,然后利用两个map来表示“索引”,键值对中的值是指向内存中结构

    2024年02月03日
    浏览(38)
  • 适用于快速开发应用的Golang二次框架

    适用于快速开发应用的Golang二次框架。 GinSkeleton 项目简介 1.这是一个基于go语言gin框架的web项目骨架,专注于前后端分离的业务场景,其目的主要在于将web项目主线逻辑梳理清晰,最基础的东西封装完善,开发者更多关注属于自己的的业务即可。 2.本项目骨架封装了以tb_users表

    2024年02月07日
    浏览(42)
  • golang 通用的 grpc http 基础开发框架

    golang 通用的 grpc http 基础开发框架 仓库地址: https://github.com/webws/go-moda 仓库一直在更新,欢迎大家吐槽和指点 transport: 集成 http(echo、gin)和 grpc。 tracing: openTelemetry 实现微务链路追踪 pprof: 分析性能 config: 通用的配置文件读取模块,支持 toml、yaml 和 json 格式。 logger: 日志系统

    2024年02月10日
    浏览(38)
  • golang能做大数据开发吗?主流的开发框架有哪些?

    Golang 在大数据领域的应用越来越广泛,可以处理大规模的数据集,同时具有高并发,低延迟和高可用性等优点。 以下是 Golang 在大数据领域中的一些主流开发框架: Apache Arrow :一种开放式的内存数据结构,用于在大数据系统中高效地传输和处理数据。 Apache Beam :一种流式数

    2024年02月13日
    浏览(48)
  • 使用Golang Web3库进行区块链开发

    区块链作为一种分布式账本技术,在近年来取得了巨大的发展。而Golang作为一种高效、并发性强的编程语言,被广泛用于区块链开发中。在Golang中,我们可以使用Web3库来与以太坊或其他区块链网络进行交互。 Web3库是一个用于与区块链进行交互的工具库。它提供了一套API,用

    2024年02月07日
    浏览(53)
  • golang web学习随便记6-模板引擎

    以下代码是几乎最简单的一个模板,{{ . }} 表示执行模板时将嵌入的数据 程序也足够简单,就是解析模板文件得到模板对象,执行模板输出结果 运行结果为 模板可以是模板文件,也可以是字符串,在上述代码中添加一个处理器函数 其实,对于文件模板,也是可以先 New一个模

    2024年02月05日
    浏览(32)
  • golang web学习随便记4-内存、文件、数据库

    我们来开始学习如何存储数据。书中有一点不错,就是并不是一上来就告诉你存储数据使用数据库,因为不同的数据存储适合不同的手段。 先来看在内存中存储数据:下面的例子用结构体方式在内存存放数据,然后利用两个map来表示“索引”,键值对中的值是指向内存中结构

    2024年02月06日
    浏览(248)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包