# cloudgo
**Repository Path**: curious_Li/cloudgo
## Basic Information
- **Project Name**: cloudgo
- **Description**: No description available
- **Primary Language**: Go
- **License**: MIT
- **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 服务程序
## 任务内容
开发简单 web 服务程序 cloudgo,了解 web 服务器工作原理。
## 任务要求
### 基本要求
1. 编程 web 服务程序 类似 cloudgo 应用。
- 支持静态文件服务
- 支持简单 js 访问
- 提交表单,并输出一个表格(必须使用模板)
2. 使用 curl 测试,将测试结果写入 README.md
3. 使用 ab 测试,将测试结果写入 README.md。并解释重要参数。
### 扩展要求
选择以下一个或多个任务,以博客的形式提交。
1. 通过源码分析、解释一些关键功能实现
2. 选择简单的库,如 mux 等,通过源码分析、解释它是如何实现扩展的原理,包括一些 golang 程序设计技巧。
## 基本要求实现
### 支持静态文件服务
```go
mx.PathPrefix("/static").Handler(http.StripPrefix("/static/",http.FileServer(http.Dir(webRoot+"/assets/"))))
```
静态文件访问路径用独立前缀“static”,将开头为“/static”的 URL 路径重定位到 /assets 文件夹中。
静态访问 /assets/js 文件夹。
访问 hello.js 文件
### 支持简单 js 访问
在 index.html 文件中访问 /assests/js/hello.js
*在此采用了百度的 jQuery 在线引用地址,老师示例中地址在我的虚拟机无法访问*
```html
...
JavaScript returns:
...
```
其中 hello.js 会通过请求 http://localhost:8080/api/test 获得 JSON 数据,然后拼接到 class “jres” 中元素后
```javascript
$(document).ready(function() {
$.ajax({
url: "/api/test"
}).then(function(data) {
$('.jres').append(data.jres);
});
});
```
返回字符串 “Hello from JS!”
```go
func apiTestHandler(formatter *render.Render) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
formatter.JSON(w, http.StatusOK, struct {
Jres string `json:"jres"`
}{Jres: "Hello from JS!"})
}
}
```
访问 index,可以看到访问 JavaScript 成功
### 提交表单,并输出一个表格
模板提交网页
```html
...
...
Press the button to compute sum of the two number
```
点击 submit 后发送数据到 /output,服务器调用 formHandler,利用 template 获取其中的数据,进行加和操作后使用 formatter 的 HTML 直接将数据注入模板,并输出到浏览器
```go
/* server.go */
mx.HandleFunc("/output", formHandler(formatter)).Methods("POST")
/* form.go */
func formHandler(formatter *render.Render) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
req.ParseForm()
fnum, err1 := strconv.Atoi(template.HTMLEscapeString(req.Form.Get("fnum")))
lnum, err2 := strconv.Atoi(template.HTMLEscapeString(req.Form.Get("lnum")))
var sum int
if err1 != nil || err2 != nil{
sum = 0
}else{
sum = fnum + lnum
}
formatter.HTML(w, http.StatusOK, "output", struct {
Fnum int `json:"fnum"`
Lnum int `json:"lnum"`
Sum int `json:"sum"`
}{Fnum: fnum, Lnum: lnum, Sum: sum})
}
}
```
表单网页
```html
The answer:
| Number1 |
Number2 |
Sum |
| {{.Fnum}} |
{{.Lnum}} |
{{.Sum}} |
```
### curl测试
```shell
curl -v http://localhost:8080
```
```shell
curl -v http://localhost:8080/api/test
```
测试表格提交,获得 output 返回的 html,可以看到得到预期结果 2+3=5
```shell
curl -v -d "fnum=2&lnum=3" "localhost:8080/output"
```
### ab测试
```shell
$ ab -n 1000 -c 100 http://localhost:8080/
```
测试结果
```shell
This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
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: 8080
Document Path: /
Document Length: 794 bytes
Concurrency Level: 100
Time taken for tests: 0.079 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 911000 bytes
HTML transferred: 794000 bytes
Requests per second: 12661.91 [#/sec] (mean)
Time per request: 7.898 [ms] (mean)
Time per request: 0.079 [ms] (mean, across all concurrent requests)
Transfer rate: 11264.65 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 1.5 1 12
Processing: 0 6 4.6 5 17
Waiting: 0 6 4.4 5 17
Total: 0 7 5.1 6 24
Percentage of the requests served within a certain time (ms)
50% 6
66% 8
75% 10
80% 13
90% 16
95% 18
98% 19
99% 20
100% 24 (longest request)
```
#### 解释重要参数
命令中的参数
```
-n:请求执行的数量
-c:并发请求的个数
-t:基准测试的最大秒数
-s:响应等待的最大秒数
-p/-u:包含了需要 POST/PUT 的数据的文件
-T:POST/PUT 的数据的 Content-type 头信息
```
结果中的参数
```
Document Path:请求的URL中根绝对路径
Document Length:Http响应数据的的长度
Concurrency Level:并发个数
Time taken for tests:所有请求处理完成所用的总时间
Complete requests:总请求数
Failed requests:失败的请求数
Requests per second:平均每秒的请求数/吞吐率
Time per request:每个请求平均消耗的时间
Time per request(mean, across all concurrent requests):上面的平均时间除以并发数
Transfer rate:单位时间内从服务器获取的数据长度
Percentage of the requests served within a certain time:每个请求处理时间的分布情况,结果中“66% 8”,代表66%的请求处理时间不超过8ms
```
## 扩展要求
[源代码分析](./源代码分析.md)