文章目录
开发 web 服务程序 - Calculator
前言
主要工作:
- 熟悉 go 服务器工作原理
- 基于现有 web 库,编写一个简单 web 应用类似 cloudgo。
- 使用 curl 工具访问 web 程序
- 对 web 执行压力测试
完整代码:Github
前期工作
框架选择
虽然我这个web程序只是一个很简单的应用,但为了了解框架的使用,我选择了Martini进行web开发。
Martini具有以下功能:
- 使用极其简单.
- 无侵入式的设计.
- 很好的与其他的Go语言包协同使用.
- 超赞的路径匹配和路由.
- 模块化的设计 - 容易插入功能件,也容易将其拔出来.
- 已有很多的中间件可以直接使用.
- 框架内已拥有很好的开箱即用的功能支持.
- 完全兼容http.HandlerFunc接口.
框架使用方法阅读
在进行实验之前,当然需要了解Martini如何使用。阅读Martini。
给出的例子如下,这样运行之后就会在localhost:3000上运行一个web程序。
package main
import "github.com/go-martini/martini"
func main() {
m := martini.Classic()
m.Get("/", func() string {
return "Hello world!"
})
m.Run()
}
看上面代码,可以知道m.Run()
是默认运行在3000端口,如果想要自定义端口则使用m.RunOnAddr(":8080")
则可以该为8080,使用例子m.RunOnAddr(":" + port)
,记得port前一定要加:
,否则会出错。
除了m.Get之外还有其他路由:
m.Get("/", func() {
// 显示
})
m.Patch("/", func() {
// 更新
})
m.Post("/", func() {
// 创建
})
m.Put("/", func() {
// 替换
})
m.Delete("/", func() {
// 删除
})
m.Options("/", func() {
// http 选项
})
m.NotFound(func() {
// 处理 404
})
暂时可以用到的不多,所以就先开始实操吧!
程序架构以及关键代码
程序架构说明
- main.go为主程序入口
- service/server.go使用框架建立一个服务器
- static为加载文件使用到的静态资源
- templates内含render渲染的HTML文件
关键代码分析
main.go
这个是参照课堂上的代码编写的,主要是设置了端口(或者获取命令行参数输入的端口)并调用server.go的函数启动服务器。
package main
import (
"os"
"github.com/github-user/cloudgo/service"
flag "github.com/spf13/pflag"
)
const (
PORT string = "8080"
)
func main() {
//获取自定义的环境变量PORT作为端口值
port := os.Getenv("PORT")
//设置默认端口值
if len(port) == 0 {
port = PORT
}
//获取命令行参数-p作为端口值
pPort := flag.StringP("port", "p", PORT, "PORT for httpd listening")
flag.Parse()
if len(*pPort) != 0 {
port = *pPort
}
//运行服务器
service.Run(port)
}
server.go
代码很短很简单,就是使用了Martini框架启动了一个web服务器。同时这里我渲染了一个HTML文件,这个文件是之前Web2.0课程上写过的一个计算器,这次作业就直接返回一个HTML即可。以前也写过一些注册登陆的功能的web,这次就不搞那么麻烦了,所以没有post路由,就一个get路由即完成。
package service
import (
"net/http"
"github.com/go-martini/martini"
"github.com/unrolled/render"
)
//Run 运行服务器
func Run(port string) {
m := martini.Classic()
//加载j静态资源
m.Use(martini.Static("static"))
m.Get("/", func(res http.ResponseWriter, req *http.Request) {
r := render.New()
//渲染HTML文件
r.HTML(res, http.StatusOK, "index", "World")
})
m.RunOnAddr(":" + port)
}
index.tepl
就是一个html文件,因为render渲染需要以这样的规则编写文件。同时还有用到的CSS与JS文件放置在静态资源文件目录下。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Calculator</title>
<meta http-equiv="Content-Type" content="text/html;
charset=utf-8" />
<link href="style.css" type="text/css" rel="stylesheet" />
<script src="script.js" ></script>
<link rel="icon" href="image/calculator.png">
</head>
<body>
<div id = "whole">
<h1>Calculator</h1>
<div id = "window">
<span id="result">0</span>
</div>
<div>
<ul>
<li id = "left" class = "dark" onclick = "calculate('(');">(</li>
<li id = "right" class = "dark" onclick = "calculate(')');">)</li>
<li id = "delete" class = "dark" onclick="calculate('d')">←</li>
<li id = "div" class = "dark" onclick="calculate('/');">/</li>
<li id = "sev" class = "num" onclick="calculate('7')">7</li>
<li id = "eig" class = "num" onclick="calculate('8')">8</li>
<li id = "nin" class = "num" onclick="calculate('9')">9</li>
<li id = "mul" class = "dark" onclick="calculate('*')">*</li>
<li id = "for" class = "num" onclick="calculate('4')">4</li>
<li id = "fiv" class = "num" onclick="calculate('5')">5</li>
<li id = "sex" class = "num" onclick="calculate('6')">6</li>
<li id= "sub" class = "dark" onclick="calculate('-')">-</li>
<li id = "one" class = "num" onclick="calculate('1')">1</li>
<li id = "two" class = "num" onclick="calculate('2')">2</li>
<li id = "thr" class = "num" onclick="calculate('3')">3</li>
<li id = "add" class = "dark" onclick="calculate('+')">+</li>
<li id = "clear" class = "dark" onclick = "calculate('c');">CE</li>
<li id = "zero" class = "num" onclick="calculate('0')">0</li>
<li id = "point" class = "dark" onclick="calculate('.')">.</li>
<li id = "equal" class = "dark" onclick="calculate('=')">=</li>
</ul>
</div>
</div>
</body>
</html>
结果展示
- 运行程序
- 访问localhost:9000
出现了我实现的一个计算器,功能完善哦!
服务器这样输出:
- curl 工具访问 web 程序
完整输出:
* About to connect() to localhost port 9000 (#0)
* Trying ::1...
* Connected to localhost (::1) port 9000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:9000
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< Date: Sun, 10 Nov 2019 05:09:14 GMT
< Transfer-Encoding: chunked
<
<!DOCTYPE html>
<html lang="en">
<head>
<title>Calculator</title>
<meta http-equiv="Content-Type" content="text/html;
charset=utf-8" />
<link href="style.css" type="text/css" rel="stylesheet" />
<script src="script.js" ></script>
<link rel="icon" href="image/calculator.png">
</head>
<body>
<div id = "whole">
<h1>Calculator</h1>
<div id = "window">
<span id="result">0</span>
</div>
<div>
<ul>
<li id = "left" class = "dark" onclick = "calculate('(');">(</li>
<li id = "right" class = "dark" onclick = "calculate(')');">)</li>
<li id = "delete" class = "dark" onclick="calculate('d')">←</li>
<li id = "div" class = "dark" onclick="calculate('/');">/</li>
<li id = "sev" class = "num" onclick="calculate('7')">7</li>
<li id = "eig" class = "num" onclick="calculate('8')">8</li>
<li id = "nin" class = "num" onclick="calculate('9')">9</li>
<li id = "mul" class = "dark" onclick="calculate('*')">*</li>
<li id = "for" class = "num" onclick="calculate('4')">4</li>
<li id = "fiv" class = "num" onclick="calculate('5')">5</li>
<li id = "sex" class = "num" onclick="calculate('6')">6</li>
<li id= "sub" class = "dark" onclick="calculate('-')">-</li>
<li id = "one" class = "num" onclick="calculate('1')">1</li>
<li id = "two" class = "num" onclick="calculate('2')">2</li>
- ab进行压力测试
完整输出:
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software:
Server Hostname: localhost
Server Port: 9000
Document Path: /
Document Length: 2288 bytes
Concurrency Level: 100
Time taken for tests: 0.435 seconds
Complete requests: 1000
Failed requests: 0
Write errors: 0
Total transferred: 2384000 bytes
HTML transferred: 2288000 bytes
Requests per second: 2300.26 [#/sec] (mean)
Time per request: 43.473 [ms] (mean)
Time per request: 0.435 [ms] (mean, across all concurrent requests)
Transfer rate: 5355.29 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 2 1.5 2 7
Processing: 6 39 15.8 39 100
Waiting: 1 30 15.6 28 98
Total: 6 42 15.6 41 100
Percentage of the requests served within a certain time (ms)
50% 41
66% 48
75% 51
80% 54
90% 66
95% 71
98% 76
99% 79
100% 100 (longest request)
未来工作
这次只是大概的了解一下如何使用框架进行web开发,未来就可以实现一些逻辑更加复杂的web程序,如加上一些登陆注册等功能。