Golang【Web 入门】 07 路由 - http.ServeMux

news2024/11/18 12:35:21

阅读目录

  • 说明
  • ServeMux 和 Handler
    • 重构:区分不同的 Handler
    • 查看 http.HandleFunc 源码
    • 重构:使用自定义的 ServeMux
    • http.ServeMux 的局限性
      • URI 路径参数
      • 请求方法过滤
      • 不支持路由命名
      • http.ServeMux 的优缺点
    • 标准库里的就是最好的?

说明

goblog 需要一款灵活的路由器来搭配 MVC 程序结构。

Go Web 开发有各式各样的路由器可供选择,我们先来看下 Go 标准库 net/http 包里的 http.ServeMux。

ServeMux 和 Handler

Go 语言中处理 HTTP 请求主要跟两个东西相关:ServeMux 和 Handler。

ServeMux 本质上是一个 HTTP 请求路由器(或者叫多路复用器,Multiplexor)。它把收到的请求与一组预先定义的 URL 路径列表做对比,然后在匹配到路径的时候调用关联的处理器(Handler)。

http 的 ServeMux 虽听起来陌生,事实上我们已经在使用它了。

重构:区分不同的 Handler

先来重构下我们的代码,修改如下:

main.go

package main

import (
	"fmt"
	"net/http"
)

func defaultHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	if r.URL.Path == "/" {
		fmt.Fprint(w, "<h1>Hello, 欢迎来到 goblog!</h1>")
	} else {
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprint(w, "<h1>请求页面未找到 :(</h1>"+
			"<p>如有疑惑,请联系我们。</p>")
	}
}

func aboutHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, "此博客是用以记录编程笔记,如您有反馈或建议,请联系 "+
		"<a href=\"mailto:summer@example.com\">summer@example.com</a>")
}

func main() {
	http.HandleFunc("/", defaultHandler)
	http.HandleFunc("/about", aboutHandler)
	http.ListenAndServe(":3000", nil)
}

浏览器访问以下三个链接,发现与之前一致:

  • localhost:3000/
  • localhost:3000/about
  • localhost:3000/no-where

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

查看 http.HandleFunc 源码

在 VSCode 编辑器里,把鼠标放置在 main 方法中的 http.HandleFunc 上,并同时按住 Ctrl 键(不要松开),当出现下划线的时候,点击进去:

在这里插入图片描述
此时我们看到的代码,是 net/http 包的源码。
显而易见,http 包也是由 Go 代码实现的。

仔细看下 HandleFunc 函数的定义:

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    DefaultServeMux.HandleFunc(pattern, handler)
}

参数:

  • pattern 是 URI 的规则,例如 / 或者 about。
  • handler 是供调用的函数。

http.HandleFunc() 函数是对 DefaultServeMux.HandleFunc() 的封装,而我们在用相同的方法查看 http.ListenAndServe() 的源码:

在这里插入图片描述
注释里有这么一段:

The handler is typically nil, in which case the DefaultServeMux is used。

handler 通常为 nil,此种情况下会使用 DefaultServeMux。

重构:使用自定义的 ServeMux

main.go

.
.
.

func main() {
    router := http.NewServeMux()

    router.HandleFunc("/", defaultHandler)
    router.HandleFunc("/about", aboutHandler)

    http.ListenAndServe(":3000", router)
}

浏览器访问以下三个链接,与之前一致:

  • localhost:3000/
  • localhost:3000/about
  • localhost:3000/no-where

http.ServeMux 的局限性

http.ServeMux 在 goblog 中使用,会遇到以下几个问题:

  • 不支持 URI 路径参数
  • 不支持请求方法过滤
  • 不支持路由命名

URI 路径参数

例如说博客详情页,我们的 URI 是 articles/1 这样来查看 ID 为 1 的文章。

http.ServeMux 也可以实现,新增一个路由作为示范:

main.go

func main() {
    router := http.NewServeMux()

    router.HandleFunc("/", defaultHandler)
    router.HandleFunc("/about", aboutHandler)

    // 文章详情
    router.HandleFunc("/articles/", func(w http.ResponseWriter, r *http.Request) {
        id := strings.SplitN(r.URL.Path, "/", 3)[2]
        fmt.Fprint(w, "文章 ID:"+id)
    })

    http.ListenAndServe(":3000", router)
}

在这里插入图片描述

不够直观,且徒增了代码的维护成本。

请求方法过滤

无法直接从路由上区分 POST 或者 GET 等 HTTP 请求方法,只能手动判断,例如:

main.go

func main() {
	router := http.NewServeMux()

	router.HandleFunc("/", defaultHandler)
	router.HandleFunc("/about", aboutHandler)

	// 列表 or 创建
	router.HandleFunc("/articles", func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case "GET":
			fmt.Fprint(w, "访问文章列表")
		case "POST":
			fmt.Fprint(w, "创建新的文章")
		}
	})

	http.ListenAndServe(":3000", router)
}

在这里插入图片描述
我们使用 CURL 来测试下:

E:\golang\src>curl -X POST http://127.0.0.1:3000/articles
创建新的文章
E:\golang\src>

E:\golang\src>curl http://127.0.0.1:3000/articles
访问文章列表
E:\golang\src>

可以实现,但是要多出来很多代码。

不支持路由命名

路由命名是一套允许我们快速修改页面里显示 URL 的机制。

例如说我们的文章详情页,URL 是:

http://example.com/articles/{id}

项目随着时间的推移,变得非常巨大,在几十个页面里都存在这个 URI 。突然有个需求或者有其他不可控因素,要求我们修改链接为:

http://example.com/posts/{id}

那么我们只能到这个几十个页面里去修改。

使用路由命名的话,我们为 articles/{id} 这个路由命名为articles.show,几十个页面在编码时,都使用这个路由名称而不是具体的 URI,遇到修改的需求时,我们只需在定义路由这一个地方修改即可。

目前 http.ServeMux 不支持此功能。

http.ServeMux 的优缺点

如上所述,Go 开源社区里有诸多路由器可供选择,那么标准库的 http.ServeMux 对比这些路由器有什么优缺点呢?

优点

  • 标准库意味着随着 Go 打包安装,无需另行安装
  • 测试充分
  • 稳定、兼容性强
  • 简单,高效

缺点

  • 缺少 Web 开发常见的特性
  • 在复杂的项目中使用,需要你写更多的代码

开发效率和运行效率,永远是对立面。

Go 因为其诞生的背景(Google 的大流量),以及核心成员的出身(底层语言和系统的缔造者),Go 标准库选择 运行效率 高于 开发效率,所以对一些常见的功能并没有添加到标准库中,这是情有可原的。

然而在 goblog 中,我们将会有数据库等与第三方服务的请求操作,跟这类编码比起来,路由解析这点性能优化微不足道。所以在这个项目中,我们将在性能不会牺牲太大的情况下,选择 开发效率 多一点。

标准库里的就是最好的?

新手常常会认为标准库里的就是最好的。
其实不然,标准库也是由 Go 语言编写的。

就拿 net/http 来讲,GitHub 上有一个项目专门对 Go 中知名的 HTTP 路由器性能做对比,结果是第三方包 HttpRouter 比 http.ServeMux 还要快不少。

事实上,标准库最大的优点是 Go 自带。

所以不止在选择 HTTP 服务器,在选择其他解决方案时,都可以大胆的使用一些 Go 开源社区优秀的第三方包。

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

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

相关文章

【运维心得】ApacheDirectory找不到java路径的解决方案

目录 ApacheDirectory是什么&#xff1f; 问题现象描述 解决步骤 总结 本文是因为没有在网上找到类似的问题和文章&#xff0c;只能依靠自己去解决&#xff0c;既然解决了&#xff0c;就应该分享一下&#xff0c;希望能帮到需要的朋友。 ApacheDirectory是什么&#xff1f…

火山引擎 DataTester 揭秘:字节如何用 A/B 测试,解决增长问题的?

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 上线六年&#xff0c;字节跳动的短视频产品——抖音已成为许多人记录美好生活的平台。除了抖音&#xff0c;字节跳动旗下还同时运营着数十款产品&#xff0c;从资讯…

人工智能在网络安全中的重要性

介绍&#xff1a; 人工智能&#xff08;AI&#xff09;是计算机科学的一个分支&#xff0c;基于某些独特的算法和相关数学计算&#xff0c;使机器能够拥有人类的决策能力。另一方面&#xff0c;网络安全包括保护虚拟世界免受网络攻击和威胁的安全措施。人工智能能够通过采取与…

第二十一章《万年历》第1节:万年历项目简介

万年历项目实现的是一款日历软件,它能够展示出任意年份的日历,除此之外,该软件还能以红色字体标出每个月的阳历节日。 21.1.1万年历功能简介 万年历软件的运行结果如图21-1所示。 图21-1万年历软件界面 为方便讲述,此处把这个万年历的界面分成了4个区域,每个区域当中都有…

【优化发电】基于matlab差分进化算法求解单库发电优化问题【含Matlab源码 2253期】

⛄一、差分进化算法简介 如同所有的优化算法一样, 差分进化算法基于种群的进化算法。差分进化算法主要的参数主要有种群规模NP, 解空间的维数D, 缩放因子F和交叉概率Cr。D维矢量XGi[xGi,1, xGi,2, …, xi, DG], i1, 2, …, Np, 表示G代第i个个体。变异和交叉操作在每一代中产生…

NIO-ServerSocketChannel和Tomcat

ServerSocketChannel 面向流的侦听套接字的可选通道。 通过调用此类的open方法创建服务器套接字通道。 无法为任意预先存在的ServerSocket创建通道。 新创建的服务器套接字通道已打开但尚未绑定。 尝试调用未绑定的服务器套接字通道的accept方法将导致抛出NotYetBoundExcepti…

达梦数据库通过作业实现自动备份功能

达梦数据库通过作业实现自动备份功能作业功能简介一、通过DM管理工具创建备份作业(图形化配置)1.创建代理环境2.创建作业二、命令行方式配置备份作业案例1.创建代理环境2.全量备份3.增量备份4.备份清理三、JOB 运行和日志查看作业功能简介 在管理员的工作中&#xff0c;有许多…

安卓APP源码和设计报告——好再来点餐

大作业文档 项目名称&#xff1a;好再来点餐专业&#xff1a;班级&#xff1a;学号&#xff1a;姓名&#xff1a; 目 录 一、项目功能介绍3 二、项目运行环境3 1、开发环境3 2、运行环境3 3、是否需要联网3 三、项目配置文件及工程结构3 1、工程配置文件3 2、工程结构…

STC - 同时外挂扩展RAM和12864时, C库函数失效的问题

文章目录STC - 同时外挂扩展RAM和12864时, C库函数失效的问题概述笔记原理图 - 外挂XRAM原理图 - 12864错误现象总结ENDSTC - 同时外挂扩展RAM和12864时, C库函数失效的问题 概述 在写STC15实验箱4的出厂测试程序. 发现memset(buf, 0, 256)一片256字节的xdata内存时, 无法将这…

生产型企业如何搭建进销存管理系统?低代码平台了解一下

生产型企业在激烈的市场竞争中充分意识到信息化管理的重要性&#xff0c;但限于资金压力无法购买或开发大型的ERP 系统整合企业管理的小型企业而言&#xff0c;比较多的采用部署相对独立的小型信息系统提高管理信息化水平&#xff0c;常见的包括采购管理系统、销售管理系统、库…

Ubuntu开机自动挂载SD卡到指定挂载点并将Docker默认存储路径改为SD卡

Ubuntu开机自动挂载SD卡到指定挂载点并将Docker默认存储路径改为SD卡查看磁盘信息查看磁盘原挂载点永久开机自动挂载分区——修改文件/etc/fstab应用挂载修改docker默认存储路径查看磁盘信息 sudo fdisk -l如果磁盘太多可以用 sudo fdisk -l | grep GiB只看以GB为单位的磁盘&…

【D3.js】2.2-给 Circle 元素添加属性

title: 【D3.js】2.2-给 Circle 元素添加属性 date: 2022-12-02 15:19 tags: [JavaScript,CSS,HTML,D3.js,SVG] 上章节中虽然添加了circle&#xff0c;但是因为缺少某些属性设置而显得不可见&#xff0c;在此章节中将学习circle的cx、cy、r属性。 一、学习目标 circle的x坐标与…

带你玩转序列模型之NLP与词嵌入(一)

目录 一.词汇表征 二.使用词嵌入 三.词嵌入的特性 四.嵌入矩阵 五.学习词嵌入 一.词汇表征 上周我们学习了RNN、GRU单元和LSTM单元。本周你会看到我们如何把这些知识用到NLP上&#xff0c;用于自然语言处理&#xff0c;深度学习已经给这一领域带来了革命性的变革。其中一…

嵌入式 ADC使用手册完整版 (188977万字)(附源码详细篇)

嵌入式 ADC使用手册完整版 &#xff08;188977万字&#xff09;&#x1f49c;&#xff08;附源码详细篇&#xff09;&#x1f49c;【1】ADC简介【2】ADC主要特征【3】ADC引脚和内部信号【4】ADC 模块框图【5】ADC校准&#xff08;CLB&#xff09;【6】ADC 时钟【7】ADCON 开关【…

Gomodule和GoPath

GoLang生态系统 什么是GOROOT GOROOT 是环境变量&#xff0c;它的值是 Golang 安装包路径 什么是GOPATH GOPATH 是Golang 1.5版本之前一个重要的环境变量配置&#xff0c;是存放 Golang 项目代码的文件路径。 可以通过go env命令查看 GOPATH目录 进入GOPATH目录&#xff…

【Docker】redis分片集群搭建:3主3从,容错迁移,扩缩容

Docker是基于Go语言实现的云开源项目。Docker的主要目标是**“Build&#xff0c;Ship and Run Any App,Anywhere”**。也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理&#xff0c;使用户的APP&#xff08;可以是一个WEB应用或数据库应用等等&#xff09;及其运…

2022 ios APP最新iOS开发上架测试教程

2022 ios APP最新开发测试教程 本文详细介绍最新的在windows上进行ios app开发编译打包安装到手机测试的完整流程。介绍ios开发经常遇到的问题和解决方法&#xff0c;包括ios开发证书&#xff0c;ios开发描述文件等。 2.Apple开发常用的三个网址&#xff1a; 开发者中心&#x…

羚数智能入选 IDC关于中国制造执行系统(MES)的市场2021年度份额报告

近日&#xff0c;国际权威市场研究机构IDC发布《中国制造业 MES 市场分析及厂商份额&#xff0c;2021》&#xff0c;引起行业关注。 成立短短一年多&#xff0c;羚数智能作为国产生产运营管理软件年度代表企业&#xff08;Vendor Who Shaped the Year&#xff09;入选报告&…

LabVIEW比较LabVIEW类对象 LabVIEW接口

LabVIEW比较LabVIEW类对象 LabVIEW接口 使用比较功能比较LabVIEW类对象。 如比较同一个类的两个对象&#xff0c;例如&#xff0c;卡车类的两个对象&#xff0c;LabVIEW将比较类层次结构中所有层次的数据&#xff0c;类似于LabVIEW比较由簇组成的簇。 如比较不同类的两个对…

Coremail邮件安全:如何防范校园邮件新威胁

11月23日&#xff0c;Coremail举办《校园安全交流防护会暨新技术应用分享》直播&#xff0c;Coremail邮件安全解决方案专家刘骞&#xff0c;从目前面临的邮件安全防护难点、盗号威胁等角度提出针对教育行业的有效邮件安全解决方案。 教育行业面临邮件安全问题 问题1&#xff…