自定义http服务+中间件案例

2023年即将到来,祝2023年更好

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"time"
)

// MiddlewareFunc 中间件的函数
type MiddlewareFunc func(ctx context.Context, req interface{}) (resp interface{}, err error)

// Middleware 构建中间件函数使用
type Middleware func(MiddlewareFunc) MiddlewareFunc

// LogFile LogFile
type LogFile struct {
	logName string
}

// buildMiddleWare 构建一个中间件函数
func buildMiddleWare(handle MiddlewareFunc) MiddlewareFunc {
	var chain []Middleware
	var LogFiler LogFile
	chain = append(chain, frontHook)
	chain = append(chain, newPrintLog(LogFiler))

	middle := buildChain(chain)
	return middle(handle)
}

// buildChain 构建链
/**
把中间件的数组构建成个链
最先执行的在最外层
next执行下一个  执行顺序和数组顺序相反
*/
func buildChain(chain []Middleware) Middleware {
	return func(next MiddlewareFunc) MiddlewareFunc {
		for i := len(chain) - 1; i >= 0; i-- {
			next = chain[i](next)
		}
		return next
	}
}

// frontHook 执行前置中间件
func frontHook(next MiddlewareFunc) MiddlewareFunc {
	return func(ctx context.Context, req interface{}) (resp interface{}, err error) {
		fmt.Println("执行前置中间件")
		startTime := time.Now().UnixNano() / 1e6
		resp, err = next(ctx, req) // 执行下一个
		if err != nil {
			log.Fatal(err)
			return
		}
		endTime := time.Now().UnixNano() / 1e6
		fmt.Println("函数执行时间为:", endTime-startTime)
		return
	}
}

// newPrintLog 打印日志中间件
func newPrintLog(LogFiler LogFile) Middleware {
	return func(next MiddlewareFunc) MiddlewareFunc {
		return func(ctx context.Context, req interface{}) (resp interface{}, err error) {
			fmt.Println("打印日志中间件")
			fmt.Println(LogFiler.logName, req)
			resp, err = next(ctx, req)
			return
		}
	}
}

// customHandler 自定义函数
func customHandler(ctx context.Context, req interface{}) (resp interface{}, err error) {
	resp = req
	fmt.Println("customHandle")
	time.Sleep(time.Second)
	return
}

// router router
func router(writer http.ResponseWriter, request *http.Request) {

	MiddlewareFunction := buildMiddleWare(customHandler)
	_, err := MiddlewareFunction(context.Background(), request)
	if err != nil {
		log.Fatal(err)
		return
	}

	_, _ = writer.Write([]byte("<h1 style='color:red;'>2023水一贴</h1>"))

}

func main() {

	//注册路由
	http.HandleFunc("/", router)
	//建立监听
	err := http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", 8089), nil)

	if err != nil {
		log.Fatal(err)
		return
	}

}
本文转载于网络 如有侵权请联系删除

相关文章

  • java 静态变量 存储_Java中存储的静态方法和静态变量在哪里?「建议收藏」

    大家好,又见面了,我是你们的朋友全栈君。静态方法(实际上所有方法)以及静态变量都存储在PermGen部分,因为它们是反射数据的一部分(类相关数据,而不是与实例相关的)。需要澄清的最新情况:注意,只有变量及其技术值(原语或引用)存储在PermGen空间中。如果静态变量是对象的引用,则该对象本身存储在堆的正常部分(年轻/旧代或幸存者空间)。这些对象(除非它们是类等内部对象)是不存储在PermGen空间。例子:staticinti=1;//thevalue1isstoredinthePermGensectionstaticObjecto=newSomeObject();//thereference(pointer/memoryaddress)isstoredinthePermGensection,theobjectitselfisnot.一个关于垃圾收集的词:做不倚靠finalize()因为它不一定会跑。这完全取决于JVM何时运行垃圾收集器和收集什么,即使一个对象符合垃圾收集的条件。当然,您可以将静态变量设置为NULL,从而删除对堆上对象的引用,但这并不意味着垃圾回收器将要收集它(即使没有更

  • Nginx系列之核心模块(上)

    Nginx系列之核心模块(上)Nginx核心模块为nginx提供核心配置功能,包括静态目录配置、localtion匹配、限速以及各种优化参数,下面针对这几方面详细展开来说nginx的核心模块,此部分内容分为上下两节;1.静态服务配置之root和aliasroot和alias都可以在配置静态服务时发挥重要的作用,二者可以达到相同的功能,但是也有很大的不同,每个都有其适应的场景。alias:alias后直接加路径,实现请求路径的替换。比如:location/i/{alias/data/w3/images/;}#当访问/i/top.gif,/data/w3/images/top.gif将发送给客户端。复制在配置alias的路径时,可以包含除document_root和realpath_root外的变量。当alias用在正则模式的的localtion匹配时,localtion正则匹配中应该包含正则捕获并在alias中引用,示例如下:location~^/users/(.+\.(?:gif|jpe?g|png))${alias/data/w3/images/$1;}复制当localtion匹配a

  • 银行前置机“跪式服务”

    01PART引子银行前置机一直是个很烦的业务,技术含量不高但是特消耗精力,投入产出比又低导致从业者待遇极低。从业这15年里,印象中遇到过三次以上的银行前置机故障,每次都令人及其痛苦。讲两个大家常见的现实案例:案例1:某公司内部银行前置机多(百八十台且都是五年以上的老破过保机器)且归属及责任不清(有银行提供的,有自己采购的;历史遗留的摊子,没有明确哪些工作由那个团队负责),每次前置机故障财务同事紧急催内部运维(理由:我们XX时间要打款,如打不出去后果XX)。运维人员:“这事也不归我管啊,你们财务部自己管找我们干啥“。财务人员:”不找你们找谁,公司就一个运维部,我们又不懂技术。我不管,反正你给我修好“。然后财务老大和运维老大一合计,运维最后还的被迫协助和背锅连夜搞。案例2:某公司卖给客户一套私有云平台,客户想把银行前置机放到云平台上。可悲的是云平台不支持usb直通导致虚拟机不识别银行usb-key。客户死缠烂打,销售中间和稀泥,公司架构和研发不支持或者反馈后续版本增加这个功能(后续遥遥无期,客户又觉得你公司不靠谱);迫不得已运维强上背后通过命令行手工绑定临时解决。过几天插usb-key的物

  • JavaScript 柯里化

    一、什么是柯里化Currying——只传递给函数一部分参数来进行调用,并让它返回一个函数去处理剩下的参数。 柯里化即Currying,是一门编译原理层面的技术,用途是实现多参函数,其为实现多参函数提供了一个递归降解的实现思路——把接受多个参数的函数变换成接受第一个参数的函数,并且返回接受剩余参数且返回结果的新函数。某些编程语言中(如Haskell)就是通过柯里化技术支持多参函数这一语言特性的二、JS柯里化的实现先来写一个实现加法的函数add:functionadd(x,y){ return(x+y) }复制现在我们直接实现一个被柯里化的add函数,该函数名为curriedAdd,则根据上面的定义,curriedAdd需要满足以下条件:curriedAdd(1)(3)===4 //true varincrement=curriedAdd(1) increment(2)===3 //true varaddTen=curriedAdd(10) addTen(2)===12 //true复制满足以上条件的curriedAdd的函数可以用以下代码段实现:functioncurriedAdd(

  • url跳转漏洞原理及绕过方式

    注:本文仅供学习参考0x01url跳转原理及利用 0x02url跳转bypass 0x03url跳转修复0x01url跳转原理及利用 先走个流程说些废话,url重定向漏洞也称url任意跳转漏洞,网站信任了用户的输入导致恶意攻击,url重定向主要用来钓鱼,比如url跳转中最常见的跳转在登陆口,支付口,也就是一旦登陆将会跳转任意自己构造的网站,如果设置成自己的url则会造成钓鱼。来看个最典型的<?php $url=$_GET['URL']; header("Location:$url"); ?>复制URL没有任何限制,所以恶意用户可以提交 http://www.aaa.com/login.php?...://www.bbb.com(钓鱼网站)来生成自己的恶意链接,安全意识较低的用户很可能会以为该链接展现的内容是www.aaa.com从而可能产生欺诈行为成功跳转到百度url跳转常见出现的地方1.登陆跳转我认为是最常见的跳转类型,认证完后会跳转,所以在登陆的时候建议多观察url参数 2.用户分享、收藏内容过后,会跳转 3.跨站点认证、授权后,

  • 什么?你还在使用fastjson,性能太差了

    在现代的整个互联网的交互通信中,json表达的简洁性和文本化的特性给我们带来很大的操作便捷性。所以大量的通信都使用这种表达方式。但是对于json方式,大家有比较多的解析方式,其中阿里开源的fastjson相信是我们大家使用最多的一种。但是我们现在有一种更好的解析方式----jsoncode,maven包引用是这样的:<dependency> <groupId>cn.miludeer</groupId> <artifactId>jsoncode</artifactId> <version>1.2.4</version> </dependency>复制下面我们做个实验,比较jsoncode和fastjson两者之前的区别。比如我们解析下面这段json结构: { "json":{ "a":{ "www":"ff", "rrr":["v1","v2"] }, &

  • docker 配置redis主从配置 集群 正式部署

    前言在正式部署前,你可以先阅读前置准备,对部署过程中用到的docker、redis操作和配置有一个理解,以防在自己电脑上复现时出错。 我们将在一台windows10机器上运行多个docker容器,配置Redis主从集群。环境宿主机一台:windows10docker18.09.2目录运行master容器编写redis.conf查看ipbind{ip}:允许指定的{ip}连接。slaveof{ip}{port}:配置主从关系。daemonizeno:是否后台运行。解决WARNINGTHP解决WARNINGsomaxconn最终的dockerrun0.确立计划我们需要在主服务器查看ip,以便编写从服务器的redis.conf。然后需要修改宿主机内核的配置,解决THPWARNING。由于windows上无法直接操作虚拟linux内核,需要在容器中进行。只要把宿主机的内核修改,所有容器都会解决THPWARNING问题。之后从服务器的部署只需一句dockerrun...即可。 流程图如下: 1.运行master容器dockerrun--nameredis-master-d-v/d/docker

  • 《基于Apache Flink的流处理》读书笔记

            前段时间详细地阅读了《ApacheFlink的流处理》这本书,作者是FabianHueske&VasilikiKalavri,国内崔星灿翻译的,这本书非常详细、全面得介绍了Flink流处理,并且以气象数据的例子讲解其中的使用,我把其中一些比较重要的句子做了比较,并且分享给大家。有一些我不是很理解,需要以后慢慢去消化,我就不做详细的展开。一、传统的数据处理框架1.1事务型处理        企业在日常业务运营过程中会用到各类基于web的应用,通常是业务系统,比如订单、客户系统等等        通常一个应用对于1个或多个数据库,应用通过执行远程数据库系统的事务来读取或更新状态1.2分析型处理        存储于不同事务类型数据系统中的数据,可以为企业提供业务运营相关的分析见解,通常是将数据从业务系统的数据库中复制到数仓,然后再进行分析和查询。这个过程称为ETL。二、Flink和Spark的区别2.1共同点        高吞吐、在压力下保持正确2.2不同点:        1.本质上,Spark是微批处理,而Flink是流处理        2.Flink低延迟

  • 为什么你的static_assert不能按预期的工作?

    static_assert是c++11添加的新语法,它可以使我们在编译期间检测一些断言条件是否为真,如果不满足条件将会产生一条编译错误信息。 使用静态断言可以提前暴露许多问题到编译阶段,极大的方便了我们对代码的排错,提前将一些bug扼杀在摇篮里。 然而有时候静态断言并不能如我们预期的那样工作,今天就来看看这些“不正常”的情况,我将举两个例子,每个都有一定的代表性。 为什么我的static_assert不工作 基于静态断言可以在编译期触发,我们希望实现一个模板类,类型参数不能是int,如果违反约定则会给出编译错误信息: template<typenameT> structObj{ static_assert(!std::is_same_v<T,int>,"T不能为int"); //dosthwitha }; intmain(){ Obj<int>*ptr=nullptr; } 复制 按照预期,这段代码应该触发静态断言导致无法编译,然而实际运行的结果却是: g++--version g++(GCC)12.2.0 Copyright©2022FreeS

  • Python 获取windows硬件信息 CPU/计算机名/IP

    获取windows硬件信息 #-*-coding:utf-8-*- #@Time:2022/11/811:22 #@Author:lzc #@Email:hybpjx@163.com #@blog:https://www.cnblogs.com/zichliang #@File:getInfo.py #@Software:PyCharm importos importplatform importsocket importgetpass importwmi #获取计算机名 hostname=socket.gethostname()#platform.uname().node #获取用户名 username=getpass.getuser() #获取本地内网IP ip=socket.gethostbyname(hostname) #获取你所使用的系统名称 system_name=platform.system()#platform.uname().system #获取操作系统的位数 bit_ar=platform.architecture() #获取你所在文件夹 pwd=os

  • 浏览器从输入网址开始

    浏览器从输入网址开始 输入网址:www.baidu.com; 浏览器查找对应的IP地址:61.135.169.121,查找过程:???不一样 浏览器缓存:检查本地是否有缓存 系统缓存; 路由器缓存; ISP的DNS缓存; 递归搜索DNS服务器; 向web服务器发送http请求(建立连接3握手); 请求的URL协议/版本;GET; 请求头:设置,是否缓存,是否发送cookie等; 请求文本:参数         GET/sample.jspHTTP/1.1         Accept:image/gif.image/jpeg,*/*        Accept-Language:zh-cn        Connection:Keep-Alive&n

  • hdu 5972 Regular Number

    题意:给出一个n,有n个表达式,开头是x,代表个数,第i位能位这x个字符,给出个字符串,问有哪些符合要求的字符串 思路:bitset,我们对于每个字符串他可以匹配哪些位,然后对于那个字符串,如果该位匹配,则右移一位,所以如果该位为1代表前这么多位都是匹配的 1#include<bits/stdc++.h> 2usingnamespacestd; 3 4constintN=1002; 5bitset<N>a[11],ans; 6chars[5000006]; 7 8intmain(){ 9intn,m,x; 10scanf("%d",&n); 11for(inti=0;i<n;i++){ 12scanf("%d",&m); 13for(intj=1;j<=m;j++){ 14scanf("%d",&x); 15a[x][i]=1; 16} 17} 18scanf("%s",s); 19intl=strlen(s); 20for(inti=0;i<l;i++){ 21ans<<=1; 22ans[0]=1; 2

  • 《网络是怎样连接的》读书笔记

    5:网页打不开,QQ能上的一种解决办法:将电脑上TCP/IP设置改为自动配置DNS。 5:QQ是直接使用IP地址来连接服务器的,所以即便DNS失效,它依然可以“屹立不倒”,以至于现在有很多人把QQ当成一个排查DNS问题的“参照物”。 2:浏览器等网络应用程序实际上并不具备网络控制功能:应用程序并不是自己去控制网络,而是委托操作系统来控制网络。

  • HJ61 放苹果

    描述: 把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。  数据范围:0≤m≤10,1≤n≤10 。   动态规划理解: 定义dp[m+1][n+1],可以理解为:将0-m个苹果放入1-n个盘子的中的方法,每一行,则为将i个苹果放入1-n个盘子中的方法数。 根据m和n的关系: 1、苹果的数量少于盘子时,即m<n -->dp[i][j]=dp[i][i] 2、苹果的数量大于等于盘子时,分两种情况:   1)没有空盘子时,则从每个盘子中拿走一个苹果,摆放的方法数是一样的。dp[i][j]=dp[i-j][j]     2)有空盘子时,此种情况不太好理解:有一个空盘子时 dp[i][j]=dp[i][j-1]。其实这里的有一个空盘子,是个递归的过程dp[i][j-1]包含了dp[i][j-2],以此类推:dp[i][j-1],包含了j-1,...,1个空盘子的情况     -->有空盘子时,

  • test2

    -------------------------- -----like+repo+comment=interact -------------------------- --droptableifexistsinteract_sum; --createtableinteract_sumas --select --uid, --count(action_type)asinteract --fromtianchi_weibo.weibo_action_data_train --groupbyuid; ----------------- ---levelpoint ----------------- droptableifexistsinteract_levelpoint; createtableinteract_levelpointas select uid, case wheninteract_sum.interact>100theninteract_sum.interact*200 wheninteract_sum.interact<=100andinteract_su

  • 邻接表c源码(构造邻接矩阵,深度优先遍历,广度优先遍历,最小生成树prim,kruskal算法)

    graph.c #include<stdio.h> #include<stdlib.h> #include<limits.h> #include"aqueue.h" #defineMAX_NUM100 typedefcharnode_type; typedefstructarc_node { intpos; intdistance; structarc_node*next; }Arc_node;//保存Node节点的相邻节点信息 typedefstructnode { node_typeinfo; Arc_node*next; }Node;//保存节点信息 typedefstructgraph { Nodeadjlist[MAX_NUM]; intvertexs,brim; }Graph;//邻接表 staticArc_node*make_node(constintpos,constintdistance) { Arc_node*new_node=(Arc_node*)malloc(sizeof(Arc_node)); if(new_n

  • 服务器机房相关

    1.温度20-26/湿度40-60。 2.进机房前防静电。 3.线不能太乱,网线夹,绑好打标签。 4.硬盘绿黄色属于正常,上架时,上下服务器隔4格。上架前了解机架型号长宽。观察能不能放导轨,不行的话需要托盘。需要两个人一起上架。 5.网线一般走地线,地下静电地板下。不会走上面,机架上方有风扇排气口空调等。 6.机架机房必须配ups,能管几分钟。在突然断电的情况下,给时间缓冲让你去关机。强电先接ups,然后服务器接ups。交流电叫强电,网线光纤电话线音频视频线以及32V以内的直流电都叫弱电。强电是用作一种动力能源,弱电是用于信息传递。强电以输电线路传输,弱电的传输有有线与无线之分。无线电则以电磁波传输。 7.服务器大小一般是2U,4U,表示服务器外部尺寸的单位。常见的就是1U服务器、2U服务器、4U服务器,这些服务器的尺寸是:1U=4.445厘米,2U=4.445*2=8.89厘米,4U=4.445*4=17.78厘米。 8.服务器切换器,管理器,kvm。键盘(Keyboard)、显示器(Video)、鼠标(Mouse)的缩写,服务器间控制切换。

  • LeetCode OJ--Swap Nodes in Pairs

    https://oj.leetcode.com/problems/swap-nodes-in-pairs/ 链表的处理 /** *Definitionforsingly-linkedlist. *structListNode{ *intval; *ListNode*next; *ListNode(intx):val(x),next(NULL){} *}; */ classSolution{ public: ListNode*swapPairs(ListNode*head){ ListNode*dummy=newListNode(-1); if(head==NULL) returndummy->next; dummy->next=head; ListNode*tail=dummy; ListNode*current=head; ListNode*second=head->next; while(current&&second) { tail->next=second; current->next=second->next; se

  • ArrayList

    1、定义 ArrayList类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。 ArrayList继承了AbstractList,并实现了List接口。 ArrayList类位于java.util包中,使用前需要引入它,语法格式如下: importjava.util.ArrayList;//引入ArrayList类 ArrayList<E>objectName=newArrayList<>(); //初始化复制 E:泛型数据类型,用于设置objectName的数据类型,只能为引用数据类型。 objectName:对象名。 ArrayList是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。   2、特性 允许插入重复的元素 插入的元素是有序的 动态扩容 非线程安全,异步 动态数组的数据结构 随机访问(get set) 3、常见方法   add() 将元素插入到指定位置的arraylist中 addAll() 添加集合中的所有元素到arraylist中

  • where和having的区别

    “Where”是一个约束声明,使用Where来约束来之数据库的数据,Where是在结果返回之前起作用的,且Where中不能使用聚合函数。 “Having”是一个过滤声明,是在查询返回结果集以后对查询结果进行的过滤操作,在Having中可以使用聚合函数。       在说区别之前,得先介绍GROUPBY这个子句,而在说GROUP子句前,又得先说说“聚合函数”——SQL语言中一种特殊的函数。例如SUM,COUNT,MAX,AVG等。这些函数和其它函数的根本区别就是它们一般作用在多条记录上。 如:SELECTSUM(population)FROMvv_t_bbc;   这里的SUM作用在所有返回记录的population字段上,结果就是该查询只返回一个结果,即所有国家的总人口数。   而通过使用GROUPBY子句,可以让SUM和COUNT这些函数对属于一组的数据起作用。当你指定GROUPBYregion时,只有属于同一个region(地区)的一组数据才将返回一行值,也就是说,表中所有除region(地区)外的字段,只能通过SUM,COUNT等

  • sql xml2

    <?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.huike.clues.mapper.TbActivityMapper"><resultMaptype="TbActivity"id="TbActivityResult"><resultproperty="id"column="id"/><resultproperty="name"column="name"/><resultproperty="channel"column="channel"/><resultproperty="info"column="info"/><resultproperty="type"column="type"/><resultprop

相关推荐

推荐阅读