Iris实现reponse拦截返回客户端消息

基本思路要求

2019/3/22 22:54晚间终于走通了大致的拦截流程。

项目需求,由于项目国际化需要,本公司所有系统翻译配置信息使用集中集群方式配置在apollo配置中心里面,最好的方式当然是吧所有的状态码都统一在路由层处理,但是同事实测nginx+lua解析服务返回json严重影响路由效率,因此java项目和go项目都统一使用自身拦截器处理,降低业务层逻辑的耦合。

java spirng boot项目的拦截器很丰富,也很容易实现,问题是go使用的这个框架iris查看源码所有的返回客户端的消息直接io.write写回去,并且其本身并没有提供responseHand的相关接口。因此处理参考文章末尾写了一半的源码解析,只能自己再别写边改。

思路如下:

返回客户端的数据主要有write,wrietString,JSON,JSONP,这几种类型,当然还有文件留之类的的,这里我们并不考虑此内容,本文也不做拦截。
熟悉源码之后可以发现,整个底层都是使用go自身的http.server和io实现的,只是在上面包装了一层,我们这里也只着重关注包装的router和context这两个类和方法,它们才是http交互的关键。因为http.Hander接口它赋值的是app.Router所以Route是进行请求和回写客户端的关键。所有的htttp请求都会使用router.mainHandler进行处理,该方法会通过HandleRequest(ctx)找到系统启动时注册的url和对应的处理方法名,使用该方法处理。

router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
		ctx := cPool.Acquire(w, r)
		router.requestHandler.HandleRequest(ctx) //主要http请求入口
		cPool.Release(ctx)
	}

参数ctx则附带了大量http请求的url,参数等上下文信息,同时也是通过url找到对应处理方法后的主要入口ctx.Do(n.Handlers)

n := t.search(path, ctx.Params())
		if n != nil {
			ctx.SetCurrentRouteName(n.RouteName)
			ctx.Do(n.Handlers) //调用对应的方法进行处理
			// found
			return
		}

看到这里你应该明白了,所有的Controler中都会带上它的值contex,当然也包括上面说的给客户的回写消息,主要靠的也是它的实现接口,通过每个回写的方法拦截器中回调我们自己实现的具体拦截业务即可起到拦截内容后返回给它们继续后续处理的问题。而我们自己实现的具体拦截器当然最好是统一一个地方处理,在contex中各个write,JSON等方法统一处理即可,这样改写代码很少便可以实现拦截。

而go语言可以使用反射实现方法回调,因此实现起来还是很简单的。

http.server
Handler:{ServeHTTP(ResponseWriter, *Request)}这里既是实现了该接口的Application.Router

Application
*router.APIBuilder
*router.Router 实现了http.Handler接口
ContextPool *context.Pool 里面存放系统变量

新建 (route,Usercontroller)
ControllerActivator
router: url methond(fullpack,name)
value:

未完待续,后面我会加上更多内容:

本文作者:bamboo
email:zjcjava@163.com

具体修改方法

修改route.go方法

type Router struct {
	MyHand interface{} // 新增自定义字段
}


// the important
	router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
		ctx := cPool.Acquire(w, r)
		ctx.ResponseHandler(router.MyHand)//添加我的拦截器
		router.requestHandler.HandleRequest(ctx)
		cPool.Release(ctx)
	}

修改context.go方法

type Context interface {


	ResponseHandler(o interface{})//给context赋值方法
}


type context struct {

	//新增自定义拦截器字段
	HandResponseWriter interface{}
}

// 实现该接口
func (ctx *context) ResponseHandler(o interface{}) {
	ctx.HandResponseWriter =  o
}

// 自定义拦截器调用该自定义字段,通过方法名反射找到方法
// ResponseWriter returns an http.ResponseWriter compatible response writer, as expected.
func (ctx *context) HandResponse(str string) string {

	fmt.Println("----------HandResponse拦截START-----------------------------")

	if ctx.HandResponseWriter!=nil {
		//ctx.HandResponseWriter.HandResponseWriter(str)
		o := ctx.HandResponseWriter
		t := reflect.ValueOf(o)         //反射使用 TypeOf 和 ValueOf 函数从接口中获取目标对象信息
		mv := t.MethodByName("HandResponseWriter")
		args := []reflect.Value{reflect.ValueOf(str)}
		rs :=mv.Call(args)
		str =rs[0].Interface().(string)

	}
	fmt.Println(str)
	fmt.Println("----------HandResponse拦截END-----------------------------")


	return str
}

//使用IO之前先调用拦截方法

func (ctx *context) Write(rawBody []byte) (int, error) {
	rawBody = []byte(ctx.HandResponse(string(rawBody)))
	return ctx.writer.Write(rawBody)
}

// Writef formats according to a format specifier and writes to the response.
//
// Returns the number of bytes written and any write error encountered.
func (ctx *context) Writef(format string, a ...interface{}) (n int, err error) {
	return ctx.writer.Writef(format, a...)
}

// WriteString writes a simple string to the response.
//
// Returns the number of bytes written and any write error encountered.
func (ctx *context) WriteString(body string) (n int, err error) {
	body = ctx.HandResponse(body)
	return ctx.writer.WriteString(body)
}



// JSON marshals the given interface object and writes the JSON response to the client.
func (ctx *context) JSON(v interface{}, opts ...JSON) (n int, err error) {
	options := DefaultJSONOptions

	if len(opts) > 0 {
		options = opts[0]
	}

	ctx.ContentType(ContentJSONHeaderValue)

	if options.StreamingJSON {
		if ctx.shouldOptimize() {
			var jsoniterConfig = jsoniter.Config{
				EscapeHTML:    !options.UnescapeHTML,
				IndentionStep: 4,
			}.Froze()
			enc := jsoniterConfig.NewEncoder(ctx.writer)
			err = enc.Encode(v)
		} else {
			enc := json.NewEncoder(ctx.writer)
			enc.SetEscapeHTML(!options.UnescapeHTML)
			enc.SetIndent(options.Prefix, options.Indent)
			err = enc.Encode(v)
		}

		if err != nil {
			ctx.StatusCode(http.StatusInternalServerError) // it handles the fallback to normal mode here which also removes the gzip headers.
			return 0, err
		}
		return ctx.writer.Written(), err
	}
	jsonStr, err := json.Marshal(v)
	if err != nil {
		fmt.Println("json err: ", err)
	}
	
	//转成json字符串 调用拦截方法
	 str :=ctx.HandResponse(string(jsonStr));
	json.Unmarshal([]byte(str), v) // 调用完成解析成原对象中
	
	n, err = WriteJSON(ctx.writer, v, options, ctx.shouldOptimize())
	if err != nil {
		ctx.StatusCode(http.StatusInternalServerError)
		return 0, err
	}

	return n, err
}

使用

package routers

import "fmt"

type  MyHand struct {

}



func (ctx MyHand) HandResponseWriter(str string) string {

	fmt.Println("----------MyHand-----------------------------")
	fmt.Println(str)

	// 检查字符串是否符合基本的json格式
	if( strings.HasPrefix(str, "{") && strings.HasSuffix(str, "}")){
		// 字符串转JSON
		var obj interface{}
		err := json.Unmarshal([]byte(str), &obj)
		if err != nil {
			fmt.Println(err)
		}

		objMap := obj.(map[string]interface{}) //转成Map

		code:=objMap["code"]

		fmt.Println("状态码是:",code)

		json, err := json.Marshal(objMap)// 转回JSON
		if err != nil {
			fmt.Println("json err: ", err)
		}

		//str=`{"code":"0000","msg":"失败","data":{"stat":"bamboo"}}`
		str=string(json)

	}


	fmt.Println(str)
	fmt.Println("----------MyHand-----------------------------")

	return  str
}

给app.Router.MyHand赋值

myHand := MyHand{}
	app.Router.MyHand=myHand

参考资料

在这里插入图片描述

Iris框架源码阅读和分析
https://www.cnblogs.com/rabbix/p/10332845.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面我将介绍如何使用决策树算法来实现iris分类。 首先需要导入相关的库和数据集: ```python from sklearn.datasets import load_iris from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # 导入 iris 数据集 iris = load_iris() X = iris.data y = iris.target ``` 将数据集分为训练集和测试集: ```python # 将数据集分为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) ``` 创建决策树模型并进行训练: ```python # 创建决策树模型 clf = DecisionTreeClassifier() # 训练模型 clf.fit(X_train, y_train) ``` 在测试集上进行预测并计算准确率: ```python # 在测试集上进行预测 y_pred = clf.predict(X_test) # 计算准确率 accuracy = accuracy_score(y_test, y_pred) print("准确率为:", accuracy) ``` 完整的代码如下: ```python from sklearn.datasets import load_iris from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # 导入 iris 数据集 iris = load_iris() X = iris.data y = iris.target # 将数据集分为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 创建决策树模型 clf = DecisionTreeClassifier() # 训练模型 clf.fit(X_train, y_train) # 在测试集上进行预测 y_pred = clf.predict(X_test) # 计算准确率 accuracy = accuracy_score(y_test, y_pred) print("准确率为:", accuracy) ``` 运行结果如下: ``` 准确率为: 1.0 ``` 说明我们使用决策树算法对 iris 数据集进行分类的准确率为 100%。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值