Go Web 编程入门:验证器(上)

简介: 在这篇文章中,我们将介绍如何在 Go 中验证发送到 REST API 的数据。

前言


网络验证可能是一个难题。 有句话在 Web 开发中流传很广的原则:


我们不能相信来自客户端用户表单的任何内容。


所以我们必须在使用这些数据之前验证所有传入数据。实现 REST API 是 Go 应用程序的典型用例。 API 接受的格式错误的数据可能会导致系统其他部分出现严重错误。


最好的情况是您的数据库有一些机制来防止存储格式错误的数据。如果不这样做,这些数据可能会导致您面向客户的应用程序出现错误和意外行为(比如 SQL 注入)。


在这篇文章中,我们将介绍如何在 Go 中验证发送到 REST API 的数据。


手动验证输入


简易的 REST API


这是一个简单的 REST API 示例,使用 gorilla/mux 包构建。它是一个很棒的 HTTP 路由器,特别是对于 REST API。 API 为一个端点提供路径 /user。为简单起见,它只接受所有用户的 HTTP GET 和创建用户的 HTTP Post。此外,它没有持久性数据库,而是用切片将用户存储在内存中。

package main
import (
    "encoding/json"
    "log"
    "net/http"
    "strings"
    "github.com/gorilla/mux"
)
type User struct {
    ID                 int
    FirstName          string
    LastName           string
    FavouriteVideoGame string
    Email               string
}
func main() {
    router := mux.NewRouter()
    router.HandleFunc("/user", PostUser).Methods(http.MethodPost)
    router.HandleFunc("/user", GetUsers).Methods(http.MethodGet)
    log.Fatal(http.ListenAndServe(":8081", router))
}
var users = []User{}
var id = 0
func validateEmail(email string) bool {
    // This is obviously not a good validation strategy for email addresses
    // pretend a complex regex here
    return !strings.Contains(email, "@")
}
func PostUser(w http.ResponseWriter, r *http.Request) {
    user := User{}
    json.NewDecoder(r.Body).Decode(&user)
    // We don't want an API user to set the ID manually
    // in a production use case this could be an automatically
    // ID in the database
    user.ID = id
    id++
    users = append(users, user)
    w.WriteHeader(http.StatusCreated)
}
func GetUsers(w http.ResponseWriter, r *http.Request) {
    w.Header().Add("Content-Type", "application/json")
    if err := json.NewEncoder(w).Encode(users); err != nil {
        log.Println(err)
        w.WriteHeader(http.StatusInternalServerError)
        return
    }
}

现在让我们看看如何手动验证在请求正文中提供给此 API 的 POST 处理程序的输入。


手动验证输入


有时我们要求用户输入一些字段,但他们未能完成该字段。例如在上一节中,当我们需要用户名时。您可以使用 len 函数来获取字段的长度,以确保用户输入了某些内容。

    if len(r.Form["username"][0])==0{
        // code for empty field
    }


假设我们想在使用 Post 处理程序创建用户时根据需要设置 FirstName、LastName 和 Email。此外,我们希望电子邮件字段是有效的电子邮件地址。一种简单的方法是手动验证字段,如下所示:

if user.FirstName == "" {
   errs = append(errs, fmt.Errorf("Firstname is required").Error())
}
if user.LastName == "" {
   errs = append(errs, fmt.Errorf("LastName is required").Error())
}
if user.Email == "" || validateEmail(user.Email) {
   errs = append(errs, fmt.Errorf("A valid Email is required").Error())
}


完整示例:

package main
import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "strings"
    "github.com/gorilla/mux"
)
type User struct {
    ID                 int
    FirstName          string
    LastName           string
    FavouriteVideoGame string
    Email               string
}
func main() {
    router := mux.NewRouter()
    router.HandleFunc("/user", PostUser).Methods(http.MethodPost)
    router.HandleFunc("/user", GetUsers).Methods(http.MethodGet)
    log.Fatal(http.ListenAndServe(":8081", router))
}
var users = []User{}
var id = 0
func validateEmail(email string) bool {
    // That's obviously not a good validation strategy for email addresses
    // pretend a complex regex here
    return !strings.Contains(email, "@")
}
func PostUser(w http.ResponseWriter, r *http.Request) {
    user := User{}
    json.NewDecoder(r.Body).Decode(&user)
    errs := []string{}
    if user.FirstName == "" {
        errs = append(errs, fmt.Errorf("Firstname is required").Error())
    }
    if user.LastName == "" {
        errs = append(errs, fmt.Errorf("LastName is required").Error())
    }
    if user.Email == "" || validateEmail(user.Email) {
        errs = append(errs, fmt.Errorf("A valid Email is required").Error())
    }
    if len(errs) > 0 {
        w.Header().Add("Content-Type", "application/json")
        w.WriteHeader(http.StatusBadRequest)
        if err := json.NewEncoder(w).Encode(errs); err != nil {
        }
        return
    }
    // We don't want an API user to set the ID manually
    // in a production use case this could be an automatically
    // ID in the database
    user.ID = id
    id++
    users = append(users, user)
    w.WriteHeader(http.StatusCreated)
}
func GetUsers(w http.ResponseWriter, r *http.Request) {
    w.Header().Add("Content-Type", "application/json")
    if err := json.NewEncoder(w).Encode(users); err != nil {
        log.Println(err)
        w.WriteHeader(http.StatusInternalServerError)
        return
    }
}


可以看到这个验证方法非常冗长。我们必须定义一个自定义函数来验证常见的东西,比如电子邮件地址。让我们看看如何改进这一点。


上面只是简单通过 validateEmail 函数验证邮箱中是否含有 @ 字符:

func validateEmail(email string) bool {
    // That's obviously not a good validation strategy for email addresses
    // pretend a complex regex here
    return !strings.Contains(email, "@")
}


其实更好的方式是通过正则表达式来验证 E-mail 的有效性:

    if m, _ := regexp.MatchString(`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`, r.Form.Get("email")); !m {
        fmt.Println("no")
    }else{
        fmt.Println("yes")
    }
相关文章
|
24天前
|
自然语言处理 Java 数据库连接
掌握JSP页面编程:动态生成Web内容
【4月更文挑战第3天】Java Server Pages (JSP) 是一种用于创建动态Web内容的Java技术,它结合HTML并允许在页面中嵌入Java代码。JSP支持代码片段、表达式语言(EL)和JSTL标签库,简化动态内容生成。当服务器接收到请求时,执行JSP中的Java代码并将结果嵌入HTML返回给客户端。示例展示了如何显示当前日期和时间。JSP可与Servlet、JavaBeans、数据库等结合,用于构建功能丰富的交互式Web应用。
掌握JSP页面编程:动态生成Web内容
|
1月前
|
负载均衡 Java 中间件
使用Go语言构建高性能Web服务
Go语言作为一种快速、高效的编程语言,其在构建高性能Web服务方面具有独特优势。本文将探讨如何利用Go语言开发和优化Web服务,以实现更高的性能和可伸缩性。
|
2天前
|
SQL 关系型数据库 MySQL
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
|
3天前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
|
3天前
|
开发框架 前端开发 数据库
Python从入门到精通:3.3.2 深入学习Python库和框架:Web开发框架的探索与实践
Python从入门到精通:3.3.2 深入学习Python库和框架:Web开发框架的探索与实践
|
4天前
|
编译器 Go 开发者
Go语言入门|包、关键字和标识符
Go语言入门|包、关键字和标识符
22 0
|
12天前
|
域名解析 Linux PHP
[CTF]ctfshow web入门
[CTF]ctfshow web入门
|
12天前
|
前端开发 搜索推荐 数据安全/隐私保护
HTML标签详解 HTML5+CSS3+移动web 前端开发入门笔记(四)
HTML标签详解 HTML5+CSS3+移动web 前端开发入门笔记(四)
18 1
N..
|
1月前
|
JavaScript 前端开发 PHP
web编程的正则表达式
web编程的正则表达式
N..
10 1
|
1月前
|
安全 测试技术 网络安全
Web安全基础入门+信息收集篇
学习信息收集,针对域名信息,解析信息,网站信息,服务器信息等;学习端口扫描,针对端口进行服务探针,理解服务及端口对应关系;学习WEB扫描,主要针对敏感文件,安全漏洞,子域名信息等;学习信息收集方法及实现安全测试,能独立理解WEB架构框架,树立渗透测试开展思路!
18 0
Web安全基础入门+信息收集篇