前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >golang学习笔记之四 - web服务器与表单处理

golang学习笔记之四 - web服务器与表单处理

作者头像
躺平程序员老修
发布2023-09-05 16:11:09
1720
发布2023-09-05 16:11:09
举报

学习笔记 golang

Web服务器

我们看到上面的代码,要编写一个Web服务器很简单,只要调用http包的两个函数就可以了;如果你以前是PHP程序员,那你也许就会问,我们的nginx、apache服务器不需要吗?Go就是不需要这些,因为他直接就监听tcp端口了,做了nginx做的事情,然后sayhelloName这个其实就是我们写的逻辑函数了,跟php里面的控制层(controller)函数类似

代码语言:javascript
复制
func httpTest(w http.ResponseWriter, r *http.Request) {
    /*
    fmt.Println(w)
    */

    /*
    fmt.Println(r)
    */

    // http://localhost:89/index?name=shyzhen&password=123456
    r.ParseForm()                           // 解析参数,默认是不会解析的
    fmt.Println(r.Form)                     // URL携带的参数 (必须执行上一步解析参数,不然是空map[]) `map[name:[shyzhen] password:[123456]]`
    fmt.Println("URL:", r.URL)              // 不包括host的url, `/index?name=shyzhen&password=123456`
    fmt.Println("URL.paht:", r.URL.Path)    // 当前路由  `/index`
    fmt.Println("URL.Scheme", r.URL.Scheme)
    fmt.Println(r.Form["name"][0])          // shyzhen

    fmt.Println("----------------")

    for k, v := range r.Form {
        fmt.Println(k, v)
    }

    fmt.Fprintln(w, "hello world")          // 这个写入到w的是输出到客户端的
}

func main() {
    http.HandleFunc("/index", httpTest)

    err := http.ListenAndServe(":9527", nil)
    if err != nil {
        log.Fatal("listenandserve:", err)
    }
}

通过server.go源码可以看到go语言在每个请求都使用了goroutines,保证每个请求独立,相互不会阻塞。

代码语言:javascript
复制
func (srv *Server) Serve(l net.Listener) error {
        ...
        tempDelay = 0
        c := srv.newConn(rw)
        c.setState(c.rwc, StateNew) // before Serve can return
        go c.serve(ctx)
        ...
}

web服务器案例

  • login.gtpl
代码语言:javascript
复制
<html>
<head>
    <title></title>
</head>
<body>
<form action="/login" method="post">
    用户名:<input type="text" name="username">
    密码:  <input type="password" name="password">
    <input type="submit" value="登录">
</form>
</body>
</html>
  • login.go
代码语言:javascript
复制
func hello(w http.ResponseWriter, r *http.Request)  {
    fmt.Fprintln(w, "首页hello")
}

func login(w http.ResponseWriter, r *http.Request)  {

    fmt.Println(r.Method)
    if r.Method == "GET" {                                    // 根据访问方法类型渲染不同界面和逻辑
        //fmt.Fprintln(w, "登录界面")                         // 引入模板的话,不能有输出

        t, _ := template.ParseFiles("./view/login.gtpl")      // ParseFiles引入模板文件,返回模板和错误信息
        err := t.Execute(w, nil)                              // 渲染模板
        log.Println("err:", err)                              // 在服务端打印日志

        //log.Println("err:", t.Execute(w, nil))              // 简洁写法
    } else {
        r.ParseForm()      // 解析参数,默认是不会解析的
        fmt.Println(r.Form["username"])
        fmt.Println(r.Form["password"])

        // 生成url参数
        / *
        v := url.Values{}
        v.Set("name", "Ava")
        v.Add("friend", "Jess")
        v.Add("friend", "Sarah")
        v.Add("friend", "Zoe")

        fmt.Println("v:", v)
        fmt.Println("get name :", v.Get("name"))
        fmt.Println("get friend:", v.Get("friend"))
        fmt.Println("friend", v["friend"])
        fmt.Println("v.Encode()", v.Encode())
        */
    }
}

func main()  {
    http.HandleFunc("/", hello)
    http.HandleFunc("/login", login)

    err := http.ListenAndServe(":9527", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

Validator

常见的验证规则:是否必填(len())、数字、长度、中英文、电子邮件、手机号码等:

代码语言:javascript
复制
<html>
<head>
    <title></title>
</head>
<body>
<form action="/login" method="post">
    用户名:<input type="text" name="username">
    密码:  <input type="password" name="password">
    验证码:<input type="text" name="verifycode">
    爱好  :<input type="checkbox" name="like" value="1">1
    <input type="checkbox" name="like" value="2">2
    <input type="checkbox" name="like" value="3">3
    <input type="submit" value="登录">
</form>
</body>
</html>
代码语言:javascript
复制
func login(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()
    if r.Method == "GET" {
        t, _ := template.ParseFiles("./view/validator.gtpl")

        log.Println(t.Execute(w, nil))
    } else {
        r.ParseForm()
        //username := r.Form["username"][0]
        //password := r.Form["password"][0]
        //verifycode := r.Form["verifycode"][0]
        like := r.Form["like"]                     // checkBox必须用这种方式取值  (通过r.Form.Get()只能获取单个的值,如果是map的值,必须通过该方式来获取)

        username := r.Form.Get("username")
        password := r.Form.Get("password")
        verifycode := r.Form.Get("verifycode")
        //like := r.Form.Get("like")

        fmt.Println(username, password, verifycode, like)

        // 输入验证
        if len(username) == 0 {
            fmt.Println("用户名不能为空")
        }
        if len(password) < 6 {
            fmt.Println("密码必须大于等于6位字符")
        }
        if !isNumber(verifycode) {
            fmt.Println("验证码只能是数字")
        }
    }
}

// 数字
func isNumber(number1 string) bool {
    if m, _ := regexp.MatchString("^[0-9]+$", number1); !m {
        return false
    }
    return true
}

// 中文
func isChinese(string1 string) bool {
    if m, _ := regexp.MatchString("^\\p{Han}+$", string1); !m {
        return false
    }
    return true
}

// 英文
func isEnglish(string1 string) bool {
    if m, _ := regexp.MatchString("^[a-zA-Z]+$", string1); !m {
        return false
    }
    return true
}

// email
func isEmail(string1 string) bool {
    if m, _ := regexp.MatchString(`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`, string1); !m {
        return false
    }

    return true
}

// 手机号码
func isPhone(string1 string) bool {
    if m, _ := regexp.MatchString(`^(1[3|4|5|8][0-9]\d{4,8})$`, string1); !m {
        return false
    }
    return true
}

// 身份证
func isIDCard(string1 string) bool {
    // 验证15位身份证,15位的是全部数字
    //if m, _ := regexp.MatchString(`^(\d{15})$`, string1); !m {
    //    return false
    //}

    // 验证18位身份证,18位前17位为数字,最后一位是校验位,可能为数字或字符X。
    if m, _ := regexp.MatchString(`^(\d{17})([0-9]|X)$`, string1); !m {
        return false
    }
    return true
}

func main() {
    http.HandleFunc("/", login)

    err := http.ListenAndServe(":9527", nil)
    if err != nil {
        log.Fatal("listen err" ,err)
    }
}
  • 下拉列表 select 如果我们想要判断表单里面<select>元素生成的下拉菜单中是否有被选中的项目。有些时候黑客可能会伪造这个下拉菜单不存在的值发送给你,那么如何判断这个值是否是我们预设的值呢?

我们的select可能是这样的一些元素

代码语言:javascript
复制
<select name="fruit">
<option value="apple">apple</option>
<option value="pear">pear</option>
<option value="banana">banana</option>
</select>

那么我们可以这样验证,遍历所有的option值,查看是否有相等的

代码语言:javascript
复制
slice:=[]string{"apple","pear","banana"}

v := r.Form.Get("fruit")
for _, item := range slice {
    if item == v {
        return true
    }
}

return false
  • 单选框 Radio 单选框的判断与select相似,要对传递过来的值进行鉴权
代码语言:javascript
复制
<input type="radio" name="gender" value="1">男
<input type="radio" name="gender" value="2">女
代码语言:javascript
复制
slice:=[]string{"1","2"}

for _, v := range slice {
    if v == r.Form.Get("gender") {
        return true
    }
}
return false
  • 复选框 CheckBox:
代码语言:javascript
复制
<input type="checkbox" name="interest" value="football">足球
<input type="checkbox" name="interest" value="basketball">篮球
<input type="checkbox" name="interest" value="tennis">网球

对于复选框我们的验证和单选有点不一样,因为接收到的数据是一个slice,在上面的demo中可以看到,接收值的时候要用r.Form["name"]方式来接收

代码语言:javascript
复制
slice:=[]string{"football","basketball","tennis"}
a:=Slice_diff(r.Form["interest"],slice)
if a == nil{
    return true
}

return false

防 XSS

攻击者通常会在有漏洞的程序中插入JavaScript、VBScript、 ActiveX或Flash以欺骗用户。一旦得手,他们可以盗取用户帐户信息,修改用户设置,盗取/污染cookie和植入恶意广告等。对XSS最佳的防护应该结合以下两种方法:一是验证过滤所有输入数据,有效检测攻击;另一个是对所有输出数据进行适当的处理,以防止任何已成功注入的脚本在浏览器端运行:

代码语言:javascript
复制
fmt.Println(username)                               // <script>alert('you have been pwned')</script>
fmt.Println(template.HTMLEscapeString(username))    // 输出到服务器端&lt;script&gt;alert(&#39;you have been pwned&#39;)&lt;/script&gt;!
template.HTMLEscape(w, []byte(username))            // 输出到客户端 &lt;script&gt;alert(&#39;you have been pwned&#39;)&lt;/script&gt;!

文件上传

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Web服务器
  • web服务器案例
  • Validator
  • 防 XSS
  • 文件上传
相关产品与服务
验证码
腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档