2024.10.10
好久之前就说要记笔记,今天才刚刚落实。 放弃了用chatgpt翻译Let‘s go的想法,转去写极客兔兔的从零开始实现web框架net/http
提供了基础的Web功能,即监听端口,映射静态路由,解析HTTP报文。一些Web开发中简单的需求并不支持,需要手工实现。
- 动态路由:例如
hello/:name
,hello/*
这类的规则。 - 鉴权:没有分组/统一鉴权的能力,需要在每个路由映射的handler中实现。
- 模板:没有统一简化的HTML机制。
- …
写的这个gee框架基本就是借鉴gin,也是轻量高效的框架 今天做了博客上两天的量,把基本的架构和context实现了。就是这种(c *gee.context)啥的,后面调用就是c.string c.json 用的这个 context可以大量减少开发者写重复代码,也方便后期加中间件 遇到一个特别离谱的错误,我排查了半个小时,然后在评论区找到答案了,详细为啥我都写在框架的注释里面了
还回忆了高中生活,实验课的时候笑疯了
2024.10.11-10.12
- 动态路由实现 通过前缀树(Trie树,顾名思义,每一个节点的所有的子节点都拥有相同的前缀。)实现动态路由,之前用map存路由表,虽然索引非常高效,但只能存固定的键值对。
- 为什么要实现路由组 路由组不是有相同的前缀这么简单,可以通过给一个路由组加中间件,使它底下的路由全部都有那种功能。还有分组嵌套啥的
2024.10.13
分组控制写完了,感觉还没动态路由一半难,动态路由还没完全理解
中间件还没写,眼睛不太舒服,暂停一下把
2024.10.14
给服务器装了docker 用crontab给橙果服务器定期重启gitlab容器
2024.10.15
yml常用来写配置文件,然后它是用缩进来分级
重新启动了原先用标准库写web服务的项目 用占位符(如?)可以防止SQL注入的原因是,先解析有占位符的SQL语句,然后再把参数以纯数据的方式传入(不会解析)。
把依赖写入结构体内,然后通过这个struct将依赖注入到用到这个依赖(如数据库连接池DB)的所有handlers里面,真的好用,减少了全局的依赖,方便进行测试。
2024.10.16
反射,我的理解就是在程序执行的过程中对程序本身进行修改或者获得程序本身的信息(如判断数据类型) Go并不擅长处理数据库记录中的空值。查询到空值会报下面的错误。
中间件写了一下,越往后面写感觉自己不会的越多,以后肯定会再回来看的。
2024.10.17
调了查qq号绑定的手机号的接口,只需要创建一个命令发送就行了,post请求会复杂一点儿,需要编写请求体啥的。 看了看idcard所需要的接口,没看明白,回去再研究一下 又用了用git,又比之前熟练了一些 改了该idcard的项目结构,自己实现了依赖注入,项目结构比之前舒服多了。(明天一定要再复习一遍) 整了docker-compose但是发现gin和gorm拉不下了,所以就一直卡住
2024.10.18
中间件的基本思想是在 HTTP 处理程序链中插入另一个处理程序。中间件处理程序执行一些逻辑,例如记录请求,然后调用链中下一个处理程序的 ServeHTTP()
方法。
func myMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 在这里执行你的中间件逻辑
next.ServeHTTP(w, r)
})
}
package main
import "net/http"
func (app *application) routes() http.Handler {
mux := http.NewServeMux()
fileServer := http.FileServer(http.Dir("./ui/static/"))
mux.Handle("/static/", http.StripPrefix("/static", fileServer))
mux.HandleFunc("/", app.home)
mux.HandleFunc("/snippet/view", app.snippetView)
mux.HandleFunc("/snippet/create", app.snippetCreate)
// 在现有的链条外包裹 logRequest 中间件。
return app.logRequest(secureHeaders(mux))//这里面套了两层中间件,外面的会先执行
}
···
2024.10.19
啥也没学。上午去上了酿酒课,感觉收获很少,下午躺了一下午,好久没白天躺着了,爽的很。 晚上看了《侧耳倾听》,真的很不错。
2024.10.20
之前是多层嵌套组合中间件,很low。使用函数式编程的思路来改进这种中间件的组合方式,创建可重用、可配置的中间件链。听着就牛逼。每加一个中间件就压一层栈,然后挨个出栈调用。 https可以理解为http(应用层协议)+TLS(传输层协议/SSL的现代版本)
2024.10.21
今天才发现go的标准库里面就有可执行文件(.go),用了
2024.10.22
学了计算机网络相关知识,了解了mac地址到底是什么,了解了dns解析是啥。 ARP协议,将mac地址映射到ip地址。具体内容就就是,比如A要联系B,A会发送自己的ip与mac地址还有B的IP地址发送给局域网的所有机器,b通过识别自己的IP并通过A的IP与mac地址单独返回自己的mac地址。
2024.10.23
context包里面的withvalue方法可以将用户是否登录和用户的信息存入context里面,方便后续的中间件或者handler获取数据。
func (app *application) authenticate(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 如果会话中不存在 "authenticatedUserID",继续执行下一个处理程序。
id, ok := app.sessionManager.Get(r.Context(), "authenticatedUserID").(int)
if !ok {
next.ServeHTTP(w, r)
return
}
// 如果会话中存在用户ID,则尝试获取对应的用户信息。
user, err := app.users.Get(id)
if err != nil {
next.ServeHTTP(w, r)
return
}
// 将认证用户的信息存储在请求上下文中。
ctx := context.WithValue(r.Context(), contextKeyIsAuthenticated, true)
ctx = context.WithValue(ctx, contextKeyUser, user)
// 使用带有更新上下文的请求对象继续执行。
next.ServeHTTP(w, r.WithContext(ctx))
})
}
user, ok := r.Context().Value(contextKeyUser).(*User)
if !ok {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
2024.10.24(程序员节)
git commit的时候,必须要有-m参数
2024.10.27
今天看了职业规划的小册子,感觉收获不少
- 首先是工程化非常重要,一定要注意工程文档的编写,养成好喜欢
- 然后就是通过写小项目来学习,效率会比一直看书要高很多
- 无论在哪工作,自身的发展永远是最重要的,写东西不能糊弄,要找到最优解
- 如果在某个地方干活儿没有提升空间了,可以考虑溜了
- 谁对谁错不是问题,没人出错才是答案
单元测试
- 用来测试一下某一个处理程序(handler)能不能正常使用
- 只模拟记录相应既可
端对端测试
- 需要创建一个完整的测试服务器
- 可以检验handler在实际的开发环境中能不能正常实现(如在一些依赖中能不能正常处理,如数据库连接,日志记录,缓存等)
2024.10.28
学了计算机基础
- 与运算 可以用来保留想保留的那几位数。比如一共八位想保留前四位,那就与上11110000
- 或运算 可以用来把某几位变成1
- 异或 就是想等就是0不同就是1 有个场景我我感觉很重要
然后还可以用来交换值
- 选择数据类型一定要选择容量小易扩容的(易变,方便后续升级,比如数组是连续空间,就不易变)
- 然后就是cpu能执行的操作
- CPU 的处理流程很简单,就是按照给定的指令去执行,CPU 的指令有以下几种。
- 数据传送指令:执行数据的读取操作,比如从寄存器读数据,将数据写入寄存器。
- 运算指令:执行算数运算和逻辑运算,比如加法运算,按位与运算,比较运算。
- 跳转指令:条件分支、循环、跳转等操作。
- 调用/返回指令:函数调用/返回操作。
- if语句,尽量让它提前结束(就是别赋值return了,满足条件就直接return)
2024.10.30
网络请求
- 尽量不请求 尽量使用缓存
- 尽量少请求 数据细化,数据压缩,数据共享等减少请求次数
- 尽量提前请求 提前预判用户操作,提前加载
进程是持有资源的最小单位,线程是系统调度的最小单位 哈希表其实是用了分页的思想(就是把哈希码相同的分到一组,这就是分页)
2024.10.31
用了学校的参数调接口,没掉明白 看了下nginx的一点点知识,略有收获 用gin写了中间件
2024.11.9
nat设备其实不仅仅是把私网IP转化成公网IP这么简单,如果一个私网下面的两个不同的设备去访问同一个服务器,转化IP加端口就显得很重要了。NAT 设备通过维护一个 NAT 表来记录内部 IP 地址和端口与外部 IP 地址和端口的映射关系。
- 逻辑同网段才能发送ARP协议
- 不一定非得是连接同一个物理交换机的网络才算一个网段,可能会有虚拟网段把多个物理网段连在一起
- 交换机:主要工作在数据链路层(第二层),用于在同一网络内(如局域网)的设备之间高效地传输数据帧。
- 路由器:主要工作在网络层(第三层),用于连接不同的网络(如局域网和广域网),并进行路由选择和数据包转发。
- 子网掩码将IP地址分为网络部分和主机部分,网络地址用于标识一个特定的网络或子网。所有属于同一个网络的设备都共享相同的网络地址。主机地址用于在同一个网络中唯一标识一个设备。每个设备在同一个网络中必须有唯一的主机地址。
- 免费arp协议是在
2024.11.15
- 数据库对比经典存储系统,方便了开发者对数据进行操作。
- 更重要的是可以执行很多复杂查询
2024.11.17
redis 纯用c写的,性能很好
Redis 的持久化
- 内存存储与数据丢失: Redis 将数据存储在内存中,因此访问速度非常快,但断电后数据会丢失。因此 Redis 提供了两种主要的持久化机制:
- RDB(Redis DataBase): RDB 是一种快照方式,它会周期性地将数据以二进制快照的形式保存到磁盘上,适合数据备份场景。
- AOF(Append-Only File): AOF 通过将每次写操作以日志形式追加写入文件来实现数据的持久化,能够更好地保证数据的完整性。
Redis 的数据结构
- SDS(Simple Dynamic String): Redis 的字符串底层实现是 SDS(Simple Dynamic String)。它不仅支持动态扩容,还能记录已使用长度和剩余空间长度,避免了 C 语言字符串
strlen
的高频计算操作,性能更高。 - List(列表): Redis 的 List 有两种底层实现:双向链表和 listpack。
- 双向链表: 用于存储较多、较大的元素。
- listpack: 是一种紧凑型结构,用于存储小量元素或较短字符串的列表数据,一个节点可以存储多个数据,从而节省内存空间。Redis 会根据数据量大小动态切换底层实现。
- Hash(哈希): Redis 的哈希表实现了渐进式 rehash(rehashing)。在扩容或缩容过程中,Redis 会将 rehash 操作分散到多个用户访问操作中进行,避免一次性 rehash 造成性能阻塞,从而保证用户访问的平稳性。
2024.10.18
hash加跳跃表(可以用来做排行榜)
redis是单线程处理,阻塞之后很麻烦
- 对于大key,可以分解key或者压缩key
- 对于热key,可以将数据直接放在本机的内存,也就是goland里面,例如可以没两秒从redis里面更新一次。这样redis的压力会小很多。关键是不用再调下一层的逻辑了。也可以拆分存到多个redis数据库,但是更新时需要更新多个key,并且可能会短暂的造成数据不一致。
不是牢底,你有什么实力
看不懂一点
 ̄﹃ ̄