# web **Repository Path**: yin-rui-2000/web ## Basic Information - **Project Name**: web - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-11-23 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # web [![Badge](https://camo.githubusercontent.com/fce1dafb36f344f3caac8b9d6be435ba810e36ab/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c696e6b2d3939362e6963752d2532334646344435422e7376673f7374796c653d666c61742d737175617265)](https://996.icu/#/en_US) [![LICENSE](https://camo.githubusercontent.com/a72e7743f15db219a6aba534f9de456e86268dd6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d416e74692532303939362d626c75652e7376673f7374796c653d666c61742d737175617265)](https://github.com/996icu/996.ICU/blob/master/LICENSE) [![Slack](https://camo.githubusercontent.com/ce1c0a467b6f4bebada87457a2e767eeb28f586c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f736c61636b2d3939366963752d677265656e2e7376673f7374796c653d666c61742d737175617265)](https://join.slack.com/t/996icu/shared_invite/enQtNjI0MjEzMTUxNDI0LTkyMGViNmJiZjYwOWVlNzQ3NmQ4NTQyMDRiZTNmOWFkMzYxZWNmZGI0NDA4MWIwOGVhOThhMzc3NGQyMDBhZDc) [![HitCount](https://camo.githubusercontent.com/a84c5e110399056a137db398775bd565e802bbba/687474703a2f2f686974732e6477796c2e696f2f3939366963752f3939362e4943552e737667)](http://hits.dwyl.io/996icu/996.ICU) 本项目实现了使用go语言完成的一个简单web程序,通过填写问卷表单,提交跳转到一个动态的结果网页。项目主要使用了`net/http`和`html/template`等包,能够便捷快速地构建出一个完整的微型服务器,在计算机上运行后,经过简单的配置就可以立即被外部浏览器访问。 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1123/212302_aca1a6d7_7997418.png "屏幕截图.png") ## Features - 支持静态文件服务 - 支持简单 `js` 访问 - 提交表单,并使用模板输出一个表格 - 支持路由参数解析 ## Usage ```shell $ git clone https://gitee.com/yin-rui-2000/web $ cd web $ go run web.go ``` 如果在Windows环境下,一般来讲会先询问: ![输入图片说明](https://images.gitee.com/uploads/images/2020/1123/212109_e56f3911_7997418.png "屏幕截图.png") 选择`允许访问`即可。之后在浏览器中输入`http://localhost:9090/`即可在本机测试访问项目页面: ![输入图片说明](https://images.gitee.com/uploads/images/2020/1123/212510_fada1ea5_7997418.png "屏幕截图.png") ## 设计介绍 根据项目介绍,我们已经直接实现了使用`template`输出一个动态的网页。也就是说在这个功能实现时,静态网页文件和js的功能都已经被囊括。现在我们就介绍一下此项目中各个功能的设计原理。 当然首先,我们先列出此项目所需要用的go语言包: ```go import ( "fmt" "html/template" "net/http" "os" ) ``` ### 静态文件服务 实现这个功能相对简单,实际上在我们输出的模板生成的动态网页的时候,此模板内部有对静态文件,例如图片、js文件的链接: ```html ``` 我们可以发现,在src下的填写目录是路由目录,也就是需要在服务器运行时通过此路由获取相应的文件。显然,虽然这些文件已经部署在了机器中,但是运行的服务器并不能直接将这个路由直接解析识别到本机的文件路径,从而读取文件。需要将本机的静态文件和路由相互关联,则需要使用`http.Handle`函数。 ```go http.Handle("/assets/js/", http.StripPrefix("/assets/js/", http.FileServer(http.Dir("assets/js/")))) http.Handle("/assets/images/", http.StripPrefix("/assets/images/", http.FileServer(http.Dir("assets/images/")))) ``` 这里必须解释一下此函数的两个参数,从左到右依次: 1. `pattern string`:注册的路由,比如我们上文中使用` ``` 其中上一行是我们需要使用的jquery文件,而下一行是我们需要使用的自己编写的js脚本。既然我们已经和正常html网页一样引用了这写js脚本,并且已经在静态文件服务实现,也就是使用`http.Handle`函数构建好了js文件的路由路径,那么接下来,我们只需要使用模板生成网页即可正常运作了。 ```javascript var gay = 114514 $(document).ready(function() { if($("#text").html() == "好吧,那祝您阖家欢乐"){ $("#count").html("有"+gay+"人和你不一样") }else{ $("#count").html("有"+gay+"人和你一样是gay") gay++ } }) ``` 在这里我们只实现了一个简单的访问后台数据的程序,并且将访问到的数据显示在网页中: ![有114514人和你一样是gay](https://images.gitee.com/uploads/images/2020/1123/215545_ab06e32a_7997418.png "屏幕截图.png") 当然这里的114514的数值可以是从后台数据库中读取的数值,也可以是经过程序运算得到的数值,总之通过javascript,我们可以更加便捷的更改网页上的信息。 ### 模板template 模板是go中实现动态网页的一个强有力的工具,它可以将一个固定模式的html类似的文件内容进行替换,替换为实时动态的信息,然后生成html文件接收http访问。当然模板还是以一个html类似的文件为基础的,比如我们的result.tmpl: ```html Are you a gay?
``` 你会发现模板文件的格式会有一下几个要求: 1. 一般以`.tmpl`为命名后缀; 2. 以html代码格式编写; 3. 以`{{.Text}}`为替换内容形式,其中的Text是替换单元的标识; 4. 替换单元的标识必须以大写开头,例如`Text`、`Image`。 好了,这就是我们需要为客户端展示的网页的模板,并且我们也在特定的位置设置好了替换单元,等待着替换为有用的信息生成为html。那么记下来我们需要为此模板定义一个特定的数据结构: ```go type Result struct { Text string Image string } ``` 显然,这个数据结构是完全按照模板的替换单元来定义的,有多少个单元,就有多少个变量,单元分别为什么名称,变量名称也必须一一对应,完全一致。接下来我们就可以解析模板,并用此数据结构的对象替换其中的信息了: ```go res = Result{ Text: "别乱写了,谁又不是gay呢", Image: "Im.gif", } tmpl, err := template.ParseFiles("result.tmpl") if err != nil { fmt.Println(err) os.Exit(2) } tmpl.Execute(w, res) ``` 以上就是接口函数`func survey(w http.ResponseWriter, r *http.Request)`中的主要内容了,它的确是响应相应路由访问时输出特定内容的代码。这样一来我们就可以输出动态的网页了。 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1123/222413_5133e51a_7997418.png "屏幕截图.png") ### 路由参数解析 我们在先前的代码中实现的是一个通过表单提交跳转的网页。这里表单的提交是使用`get`,将提交的信息显式的记录在url中: ![输入图片说明](https://images.gitee.com/uploads/images/2020/1123/222716_f87dd832_7997418.png "屏幕截图.png") 那么根据不同的路由参数提供不同的网页内容是一间很实用的事。我们使用以下代码实现: ```go func survey(w http.ResponseWriter, r *http.Request) { vars := r.URL.Query() ``` 使用r.URL.Query函数,注意这里的r是接口函数的一个传入参数。函数返回一个map[string][]string,也就是说我们需要通过相应的键值访问相应的值。 ```go dog, ok := vars["dog"] ``` 这样我们就得到了dog这个键值对应的值的数组了,因为只有一个值,我们直接访问下标0。 ```go if dog[0] == "不养" { res = Result{ Text: "这就说明,你是个gay", Image: "why.jpg", } } else if dog[0] == "养" { res = Result{ Text: "好吧,那祝您阖家欢乐", Image: "homo.png", } } else { res = Result{ Text: "别乱写了,谁又不是gay呢", Image: "Im.gif", } } ``` ![输入图片说明](https://images.gitee.com/uploads/images/2020/1123/223523_a3fa6713_7997418.png "屏幕截图.png") ## 测试 ### curl测试 测试主页面 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1123/223840_65ff736c_7997418.png "屏幕截图.png") 测试提交后的结果页面 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1123/223941_4f205386_7997418.png "屏幕截图.png") ### ab测试 使用以下命令测试: ```shell ab -n 1000 -c 100 http://localhost:9090/ ``` ![输入图片说明](https://images.gitee.com/uploads/images/2020/1123/225457_ec84396f_7997418.png "屏幕截图.png") ![输入图片说明](https://images.gitee.com/uploads/images/2020/1123/225528_81ccdb55_7997418.png "屏幕截图.png") #### 参数解释 有关ab命令的使用,我们可以通过帮助命令进行查看。如下: ab --help 下面我们对这些参数,进行相关说明。如下: -n在测试会话中所执行的请求个数。默认时,仅执行一个请求。 -c一次产生的请求个数。默认是一次一个。 -t测试所进行的最大秒数。其内部隐含值是-n 50000,它可以使对服务器的测试限制在一个固定的总时间以内。默认时,没有时间限制。 -p包含了需要POST的数据的文件。 -P对一个中转代理提供BASIC认证信任。用户名和密码由一个:隔开,并以base64编码形式发送。无论服务器是否需要(即, 是否发送了401认证需求代码),此字符串都会被发送。 -T POST数据所使用的Content-type头信息。 -v设置显示信息的详细程度-4或更大值会显示头信息,3或更大值可以显示响应代码(404,200等),2或更大值可以显示警告和其他信息。 -V显示版本号并退出。 -w以HTML表的格式输出结果。默认时,它是白色背景的两列宽度的一张表。 -i执行HEAD请求,而不是GET。 -x设置属性的字符串。 -X对请求使用代理服务器。 -y设置属性的字符串。 -z设置
属性的字符串。 -C对请求附加一个Cookie:行。其典型形式是name=value的一个参数对,此参数可以重复。 -H对请求附加额外的头信息。此参数的典型形式是一个有效的头信息行,其中包含了以冒号分隔的字段和值的对(如,"Accept-Encoding:zip/zop;8bit")。 -A对服务器提供BASIC认证信任。用户名和密码由一个:隔开,并以base64编码形式发送。无论服务器是否需要(即,是否发送了401认证需求代码),此字符串都会被发送。 -h显示使用方法。 -d不显示"percentage served within XX [ms] table"的消息(为以前的版本提供支持)。 -e产生一个以逗号分隔的(CSV)文件,其中包含了处理每个相应百分比的请求所需要(从1%到100%)的相应百分比的(以微妙为单位)时间。由于这种格式已经“二进制化”,所以比'gnuplot'格式更有用。 -g把所有测试结果写入一个'gnuplot'或者TSV(以Tab分隔的)文件。此文件可以方便地导入到Gnuplot,IDL,Mathematica,Igor甚至Excel中。其中的第一行为标题。 -i执行HEAD请求,而不是GET。 -k启用HTTP KeepAlive功能,即在一个HTTP会话中执行多个请求。默认时,不启用KeepAlive功能。 -q如果处理的请求数大于150,ab每处理大约10%或者100个请求时,会在stderr输出一个进度计数。此-q标记可以抑制这些信息。