go web学习(四)
跟着b站https://space.bilibili.com/361469957 杨旭老师学习做的笔记
中间件
什么是中间件
请求————> 中间件 ————> Handler
响应 <———— Middleware <———— Handler
创建中间件
func ListenAndServe(addr string, handler Handler) error
handler 如果是 nil:DefaultServeMux
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
type MyMiddleware struct {
Next http.Handler
}
func(m MyMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 在 next handler 之前做一些事情
m.Next.ServeHTTP(w, r)
// 在 next handler 之后做一些事情
}
中间件的用途
Logging
安全
请求超时
响应压缩
…
下面是例子
// 目录下
// middleware文件夹 包含auth.go
// main.go
auth.go
package middleware
import "net/http"
// 链式结构, Next 设置为 什么,下一个handler 就是什么
// AuthMiddleware ..
type AuthMiddleware struct {
Next http.Handler
}
func (am *AuthMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 如果只有一个中间件,改中间件的字段next 为nil, 交给默认路由器处理
if am.Next == nil {
am.Next = http.DefaultServeMux
}
// 判断auth
auth := r.Header.Get("Authorization")
if auth != "" {
// before 路由
am.Next.ServeHTTP(w, r)
// after 路由
} else {
w.WriteHeader(http.StatusUnauthorized)
}
}
main.go
package main
import (
"encoding/json"
"net/http"
"timer/goWeb-sql/middleware"
//middleware文件夹的位置,每个人都不一样,自己建的
)
type Company struct {
ID int
Name string
Country string
}
func main(){
http.HandleFunc("/companies", func(w http.ResponseWriter, r *http.Request){
c := Company{
ID: 123,
Name: "goolle",
Country: "USA",
}
// time.Sleep(4*time.Second)
enc := json.NewEncoder(w)
enc.Encode(c)
})
// 通过认证就能获取数据
// 使用中间件
http.ListenAndServe("localhost:8080", new(middleware.AuthMiddleware))
}
GET http://localhost:8080/companies HTTP/1.1
# with auth
GET http://localhost:8080/companies HTTP/1.1
Authorization: root
这个是加上请求上下文的
// 目录下
// middleware文件夹 包含auth.go timeout.go
// main.go
timeout.go
package middleware
import (
"context"
"net/http"
"time"
)
type TimeoutMiddleware struct {
Next http.Handler
}
func (tm TimeoutMiddleware) ServeHTTP(w http.ResponseWriter ,r *http.Request){
if tm.Next == nil{
tm.Next = http.DefaultServeMux
}
ctx:= r.Context()
ctx,_ = context.WithTimeout(ctx,3*time.Second)
r.WithContext(ctx)
ch:= make(chan struct{})
go func(){
tm.Next.ServeHTTP(w,r)
ch <- struct{}{}
}()
select{
case <- ch:
return
case<- ctx.Done():
w.WriteHeader(http.StatusRequestTimeout)
}
ctx.Done()
}
main.go
http.HandleFunc("/companies", func(w http.ResponseWriter, r *http.Request) {
c := Company{
ID: 123,
Name: "gggoolle",
Country: "USA",
}
// time.Sleep(4*time.Second) 用来测试的
enc := json.NewEncoder(w)
enc.Encode(c)
})
// 使用中间件
http.ListenAndServe("localhost:8080", &middleware.TimeoutMiddleware{
Next: new(middleware.AuthMiddleware),
})
请求上下文
(例子见上面那个)
请求可能会通过中间件,到达handler,再到model层(数据库,Web Api,文件系统),model层不应该知道在web请求的上下文操作,但是他们需要知道一些重要信息,比如超时停摆。
它可以用于在不同的 Goroutine 之间传递请求特定值、取消信号以及超时截止日期等数据,以协调 Goroutine 之间的操作。
request Context
func(*Request) Context() context.Context
返回当前请求的上下文
func(*Request) WithContext(ctx context.Context) context.Context
基于 Context 进行“修改”,(实际上)创建一个新的 Context
context.Context
type Context interface {
Deadline() (deadline time.Time, ok bool)
//返回 完成工作的截止日期
Done() <-chan struct{}
//返回一个 Channel,这个 Channel 会在当前工作完成或者上下文被取消后关闭,
//多次调用 Done 方法会返回同一个 Channel
Err() error
// 错误
Value(key interface{}) interface{}
// 从 context.Context中获取键对应的值
}
//这些方法都是用于读取,不能进行设置
Context API – 可以返回新 Context
WithCancel(),它有一个 CancelFunc
WithDeadline(),带有一个时间戳(time.Time)
WithTimeout(),带有一个具体的时间段(time.Duration)
WithValue(),在里面可以添加一些值
串联处理器和处理器函数
诸如日志,安全检查和错误处理,为了防止代码重复和代码依赖,可以使用串联技术分隔它们。
也叫做管道处理
输入——》f1 do something ——》f2 do something ——》f3 do something ——》输出
和中间件相像又不一样
串联处理器函数
// http.HandleFunc("/hello",protect(log(hello)))
func hello(w http.ResponseWriter,r *http.Request){
//
}
func log(h http.HandlerFunc) http.HandlerFunc{
return func(w http.ResponseWriter,r *http.Request){
//日志操作
h(w,r)
}
}
func protect(h http.HandlerFunc) http.HandlerFunc{
return func(w http.ResponseWriter,r *http.Request){
//一些操作
h(w,r)
}
}
串联处理器
// http.Handle("/hello",protect(log(hello)))
type HelloHandler struct{}
func (h HelloHandler) ServeHttp (w http.ResponseWriter,r *http.Request){
}
func log(h HelloHandler) http.Handler{
return http.HandlerFunc(
func(w http.ResponseWriter,r *http.Request){
//一些操作
h.ServeHttp(w,r)
}
)
}
func protectlog(h HelloHandler) http.Handler{
return http.HandlerFunc(
func(w http.ResponseWriter,r *http.Request){
//一些操作
h.ServeHttp(w,r)
}
)
}
go web学习(四)的更多相关文章
- java web 学习四(http协议)
一.什么是HTTP协议 HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的 ...
- Java Web 学习路线
实际上,如果时间安排合理的话,大概需要六个月左右,有些基础好,自学能力强的朋友,甚至在四个月左右就开始找工作了.大三的时候,我萌生了放弃本专业的念头,断断续续学 Java Web 累计一年半左右,总算 ...
- web—第四章css&第五章
web—第四章css&第五章 终于迎接等待已久的CSS,在没学这个之前,我们只会用一点img,查一点小图片,或者是用style改一下颜色,而且比较麻烦.现在多了个css在文件夹在创建一个cs ...
- [原创]java WEB学习笔记95:Hibernate 目录
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- Java Web学习系列——Maven Web项目中集成使用Spring
参考Java Web学习系列——创建基于Maven的Web项目一文,创建一个名为LockMIS的Maven Web项目. 添加依赖Jar包 推荐在http://mvnrepository.com/.h ...
- Java Web(十四) 编写MyBookStore项目的总结
这几天一直没有发博文,原因是在写一个书城的小项目,作为web学习的最后沉淀,接下来就要到框架的学习了. --WH 一.项目介绍 从网上找的一个培训机构的小项目,名称叫做 书城购物网站 吧,其中就是分前 ...
- (转)SpringMVC学习(四)——Spring、MyBatis和SpringMVC的整合
http://blog.csdn.net/yerenyuan_pku/article/details/72231763 之前我整合了Spring和MyBatis这两个框架,不会的可以看我的文章MyBa ...
- Spring Boot 项目学习 (四) Spring Boot整合Swagger2自动生成API文档
0 引言 在做服务端开发的时候,难免会涉及到API 接口文档的编写,可以经历过手写API 文档的过程,就会发现,一个自动生成API文档可以提高多少的效率. 以下列举几个手写API 文档的痛点: 文档需 ...
- Java反射:Web学习的灵魂
反射:Web学习的灵魂 我们从最初的 javac -HelloWorld.java,到面向对象部分,我们可以将Java代码在计算机中经历的阶段分为三部分:Scource源代码阶段 -- Class类对 ...
- Web学习之css
CSS指层叠样式表(Cascading Style Sheets),CSS 是标准的布局语言,用来控制元素的尺寸.颜色.排版.CSS 由 W3C 发明,用来取代基于表格的布局.框架以及其他非标准的表现 ...
随机推荐
- socket搭建web服务端
import socket from threading import Thread import time def html(conn): time_tag = str(time.time()) p ...
- Java中方法的定义及注意事项
一.方法 什么是方法: 方法(method)是程序中最小的执行单元 实际开发中,什么时候用到方法: 重复的代码.具有独立功能的代码可以抽取到方法中 实际开发中,方法有什么好处: 可以提高代码的复用性 ...
- Java实现平衡二叉搜索树(AVL树)
上一篇实现了二叉搜索树,本章对二叉搜索树进行改造使之成为平衡二叉搜索树(Balanced Binary Search Tree). 不平衡的二叉搜索树在极端情况下很容易退变成链表,与新增/删除/查找时 ...
- VS 输入快捷键propfull
大家都知道prop.propg输入快捷键. 当前我们需要生成一段包含属性和字段的代码时,可以propfull. propfull在安装了reshaper后,会被隐藏掉.没关系,直接敲propfull, ...
- [C++提高编程] 3.2 vector容器
文章目录 3.2 vector容器 3.2.1 vector基本概念 3.2.2 vector构造函数 3.2.3 vector赋值操作 3.2.4 vector容量和大小 3.2.5 vector插 ...
- Python_15 ddt驱动与日志
一.查缺补漏 1. 在测试报告中添加注释,写在类名下面就行,方法名下面,三引号 2. 直接import ddt引用的时候需要ddt.ddt, ddt.data, ddt.unpack from ddt ...
- Python数据分析中 melt()函数的一些用法
melt()函数是一个数据重塑工具,用于将宽格式数据转换为长格式数据(Unpivot a DataFrame from wide to long format, optionally leaving ...
- PaddlePaddle 飞桨复现 ResNeXt
import paddle.nn as nn import paddle class BN_Conv2D(nn.Layer): """ BN_CONV_RELU &quo ...
- 2023-01-09:以下go语言代码输出什么?A:+Inf; B:zero; C:something else; D:doesn‘t compile。 package main import (
2023-01-09:以下go语言代码输出什么?A:+Inf: B:zero: C:something else: D:doesn't compile. package main import ( & ...
- 2020-10-07:redis存在线程安全的问题吗?为什么?
福哥答案2020-10-07:#福大大架构师每日一题# Redis6.0的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程顺序执行.所以我们不需要去考虑控制 key.lua.事务, ...