Golang之我想写个"web框架"-3: 整合请求报文以及响应报文

之前我们已经看了请求报文的获取和响应报文的生成,我们这次来整合一下请求和响应报文,可以简单搞一个“框架”了。

问题回顾

响应报文生问题

我们之前测试的时候,计划让其返回<h1>hello world</h1>,结果实际上返回的是<h1>hello world</h,少了2个字节,而浏览器默认给修复了,所以我们在浏览器没有看出异常。

我们通过抓包来分析,我们发现,我们在学习报文的地方就搞错了。

我们查看我们之前画的响应报文

正确的响应报文和请求报文

上面是有问题的,在我们 首部行 和 响应主体 之间,不是\r\n\r\n进行分割的,而是\r\n进行分割的,所以说,正确的响应报文应该是这样的:

而请求报文亦然

好,此时我们修改响应报文代码,应当为

之前是responseByte = append(responseByte, []byte(CRLF2)...),我们将其修改为responseByte = append(responseByte, []byte(CRLF)...)

func buildResponsePack(rp responsePackages)([]byte) {
	responseByte := make([]byte,0)
	// 构建状态行
	// 版本
	responseByte = append(responseByte, []byte(rp.HttpVersion+" ")...)

	// 状态码
	responseByte = append(responseByte, []byte(strconv.Itoa(int(rp.StatusCode))+" ")...)

	// 短语
	responseByte = append(responseByte, []byte(rp.StatusMsg+CRLF)...)

	// 首部信息
	for k,v := range rp.responseHeader {
		responseByte = append(responseByte, []byte(k+": ")...)
		responseByte = append(responseByte, []byte(v+CRLF)...)
	}

	// 添加响应主体
	if 0 < len(rp.Body) {
		// 新增 Content-Length
		responseByte = append(responseByte, []byte("Content-Length: "+strconv.Itoa(len(rp.Body))+"\r\n")...)
	}

	responseByte = append(responseByte, []byte(CRLF)...)
	responseByte = append(responseByte, rp.Body...)

	fmt.Printf("生成响应报文\n%s\n\n\n",string(responseByte))
	return responseByte
}

这样修改的话,我们再次请求就不会遇到问题了。

整合请求报文和响应报文

我们已经将相关代码已经放到giteegitee.com/pdudo/Sampl…

我们整合后的demo大概是这样的

package main

import "gitee.com/pdudo/SampleHttp"

func main() {
	SampleHttp.Route("GET","/pdudo", func(info *SampleHttp.HttpInfo) {
		info.SetHttpStatusCode(200)
		info.Write([]byte("<h1>hello world</h1>"))
	})

	SampleHttp.Route("GET","/123", func(info *SampleHttp.HttpInfo) {
		info.SetHttpStatusCode(301)
		info.SetResponseHeader("Location","https://juejin.cn")
	})

	SampleHttp.StartServer("0.0.0.0:8082")
}

其中,SampleHttp.StartServer是启动http服务器,SampleHttp.Route是定义路由,其接收三个参数,第一个是请求的方法,第二个是路由,第三个则是函数,函数中需要传入参数*SampleHttp.HttpInfo,这个不是闭包,仅仅是将函数作为参数传递。

将函数作为参数传递

将函数形参作为参数传递不是闭包哦!

无形参参数传递

我们看个函数案例

假设我们想获取函数的执行时间,我们可以将函数作为参数传递

例如

我们定义了一个x函数,其中形参是一个函数,名称叫做fun,我们仅需要在x函数中获取一个时间,然后执行fun函数,最后再获取执行时间就可以,我们并不需要关心fun是啥,我们仅知道它是一个无形参无返回值的函数就可以了。

这样,我们在调用x的时候,就可以再其形参部分写函数了,我们假设函数中就写一个sleep30秒,我们可以执行下程序看下。

有形参的函数作为参数传递

我们还是先看demo

我们定义了一个函数x,其形参是一个函数,函数又有一个形参,为int类型的,那么我们想在x函数中调用这个函数,我们至少得声明一个int类型的变量,然后再调用。

记录路由

我们将路由信息定义为map[string]func(info *HttpInfo)形式,即,定义了一个keystring类型的map,其valueinfo *HttpInfo,再次基础上,我们给没种方法都定义了一个路由map,目前仅支持GETPOST

在记录路由的时候,我们根据其方法将函数存入不同的map中,例如

这样的话,key是我们的URLvalue则是我们的函数。

服务器工作流程

在项目中,我们调用StartServer函数

在函数中,会监听我们定义的地址,并且开始工作,我们收到请求后,我们会定义一个新的HttpInfo,然后开一个协程去处理该请求

在上述函数中,我们会拆解http协议并且放入我们HttpInfo变量中,而后根据请求协议,例如GETPOST等,我们会按照请求的URL作为mapkey去取函数值,若取到的话,我们就执行该函数,然后将HttpInfo数据组合,发回客户端。至此,流程结束。

总结

在文章中,我们总结了前面学习报文的不足,我们重新梳理了请求报文和响应报文代码,而后,我们根据前2篇文章,我们定义了一个属于自己的“框架”,用于自定义路由等,总的而言,将这几篇文章,作为入门http协议来看的话,是非常不错的,赞。

本文正在参加技术专题18期-聊聊Go语言框架

posted @ 2022-07-18 21:44  pdudos  阅读(0)  评论(0编辑  收藏  举报  来源