写点什么

如果利用 Go 创建一个 Web 应用

作者:宇宙之一粟
  • 2023-04-25
    中国香港
  • 本文字数:4239 字

    阅读完需:约 14 分钟

如果利用 Go 创建一个 Web 应用

客户端/服务器


假设你开发了一个使用 Go 语言编写的程序来管理你的照片库,这个程序可以在你的电脑上处理你的照片。你可能想与其他家庭成员分享这些照片,为此,你可以通过电子邮件发送包含所有照片的附件。但如果你拍了一万张照片,这种解决方案可能是不可行的。


您可以将内容自动上传到您最喜爱的社交网络。如果您必须一次处理一张照片,该操作可能会变得非常耗时。另一种解决方案可能是将您的程序直接插入社交网络系统,以编程方式上传图片。


我们可以借助社交网络公开的 API 来做到这一点。您可以通过直接调用它们的 API 将图片推送到 for 循环中。


在这种情况下,您将使用一个 API。你是客户端。社交网络代表服务器。


调用 API 意味着按照精确的文档向 Web 服务器发出 HTTP(s) 请求。客户端和服务器这两个术语很重要,您必须记住它们。作为客户端,我们使用(或消费)API。服务器是一个计算机程序,旨在接受和响应客户端的 API 调用。



Go 语言在创建简单高效的 Web 服务器方面很有优势。Go 语言提供了内置的 HTTP 包,其中包含了快速创建 Web 或文件服务器所需的实用工具。这使得使用 Go 语言创建 Web 服务器和 Web 服务变得简单和高效。


创建 server.go 文件


上一篇文章中,我们学习了 net/http 包中的 Request 和 Response ,所以这里我们可以直接使用:


package main
import ( "fmt" "log" "net/http")
func main() {
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello!") })
fmt.Printf("Starting server at port 8088\n")
if err := http.ListenAndServe(":8088", nil); err != nil { log.Fatal(err) }}
复制代码


运行 go run server.go ,可以在终端上看到如下输出:


Starting server at port 8088
复制代码


在此阶段,我们将创建一个实际在端口 8088 上提供服务并可以响应传入 GET 请求的 Web 服务器。让我们在端口 8088 启动 Web 服务器。ListenAndServe() 方法由我们在第一步中导入的 http 数据包导出。此方法允许我们启动 Web 服务器并指定端口以侦听传入请求。请注意,端口参数需要作为以冒号标点符号开头的字符串传递。第二个参数接受一个处理程序来为 HTTP/2 配置服务器,将 nil 作为第二个参数传递。


我们将使用 HandleFunc() 函数将路由处理程序添加到 Web 服务器。第一个参数接受它需要监听的路径 /hello。在这里,您告诉服务器监听对 http://localhost:8088/hello 的任何传入请求。第二个参数接受一个函数,该函数包含正确响应请求的业务逻辑。


默认情况下,此函数接受 ResponseWriter 以发回响应,并接受 Request 对象以提供有关请求本身的更多信息。例如,您可以访问有关已发送标头的信息,这对于验证请求很有用。



如您所见,处理程序发送了一个“Hello!”消息,因为我们将此响应传递给 ResponseWriter


路由添加基本校验

不用说,安全很重要。让我们探索一些增强 Go Web 服务器安全性的基本策略。在我们这样做之前,我们应该花点时间来提高代码的可读性。让我们创建 helloHandler 函数,它包含与 /hello 请求相关的所有逻辑。


func helloHandler(w http.ResponseWriter, r *http.Request) {    if r.URL.Path != "/hello" {        http.Error(w, "404 not found.", http.StatusNotFound)        return    }
if r.Method != "GET" { http.Error(w, "Method is not supported.", http.StatusNotFound) return }

fmt.Fprintf(w, "Hello!")}
复制代码

此处理程序使用 Request 对象检查请求的路径是否正确。这是一个非常基本的示例,说明如何使用 Request 对象。


如果路径不正确,服务器将向用户返回 StatusNotFound 错误。要向用户写入错误,您可以使用 http.Error 方法。请注意,StatusNotFound 代码对应于 404 错误。所有状态代码都可以在 Golang 文档中找到。


接下来,我们添加一个检查来验证请求的类型。如果该方法不对应于 GET,则服务器返回一个新错误。当两个检查都通过时,服务器返回其成功响应“Hello!”。


我们需要做的最后一件事是修改 main() 函数中的 handleFunc 函数以接受上面的 helloHandler 函数。

http.HandleFunc("/hello", helloHandler)
复制代码


完整的 server.go 文件如下:


package main
import ( "fmt" "log" "net/http")
func helloHandler(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/hello" { http.Error(w, "404 not found", http.StatusNotFound) return }
if r.Method != "GET" { http.Error(w, "Method is not supported", http.StatusNotFound) return }
fmt.Fprintf(w, "Hello!")}
func main() {
http.HandleFunc("/hello", helloHandler)
fmt.Printf("Starting server at port 8088\n")
if err := http.ListenAndServe(":8088", nil); err != nil { log.Fatal(err) }}
复制代码


接下来,我们将使用 go run server.go 启动 Go Web 服务器。您可以使用 Postman 或 cURL 等工具向 http://localhost:8088/hello 发送 POST 请求来测试您的安全性。我们将得到与上一次相同的结果。


启动静态 Web 服务器


在这一步中,我们将创建一个简单的文件服务器来托管静态文件。这将是对 Web 服务器的一个非常简单的添加。为确保我们有内容可在 Web 服务器上提供服务,让我们新建一个位于 static 文件夹中的 index.html 文件。为了简单起见,只需在文件中添加一个标题为“Go Server”的标题。如果您愿意,可以添加更多文件或样式文件以使您的 Web 服务器看起来更漂亮一些。


新建一个 index.html 文件:

<html>  <head>    <title>Learn Go</title>  </head>  <body>    <h2>Go Server</h2>  </body></html>
复制代码

要为 static 文件夹提供服务,您必须向 server.go 添加两行代码。第一行代码使用 FileServer 函数创建文件服务器对象。此函数接受 http.Dir 类型的路径。因此,我们必须将字符串路径“./static”转换为 http.Dir 路径类型。


不要忘记指定 Handle 路由,它接受路径和文件服务器。此函数的作用与 HandleFunc 函数相同,但有一些细微差别。有关 FileServer 对象的更多信息,请查看文档。


func main() {    fileServer := http.FileServer(http.Dir("./static"))     http.Handle("/", fileServer)    http.HandleFunc("/hello", helloHandler)

fmt.Printf("Starting server at port 8088\n") if err := http.ListenAndServe(":8088", nil); err != nil { log.Fatal(err) }}
复制代码


是时候尝试代码了。使用 go run server.go 启动服务器并访问 http://localhost:8088/。你应该看到:

接受表单提交 POST 请求

最后,Web 服务器必须响应表单提交。让我们向 static 文件夹中的 form.html 文件添加一些内容。请注意,表单操作已发送到 /form。这意味着来自表单的 POST 请求将被发送到 http://localhost:8088/form。表单本身要求输入两个变量:nameaddress


<!DOCTYPE html><html>  <head>    <meta charset="UTF-8" />  </head>  <body>    <div>      <form method="POST" action="/form">        <label>Name</label><input name="name" type="text" value="" />        <label>Address</label><input name="address" type="text" value="" />        <input type="submit" value="submit" />      </form>    </div>  </body></html>
复制代码

下一步是创建处理程序来接受 /form 请求。 form.html 文件已经通过 FileServer 提供,可以通过 http://localhost:8088/form.html 访问。


首先,该函数必须调用 ParseForm() 来解析原始查询并更新 r.PostFormr.Form。这将允许我们通过 r.FormValue 方法访问 nameaddress 值。


在函数的末尾,我们使用 fmt.Fprintf 将这两个值写入 ResponseWriter


func formHandler(w http.ResponseWriter, r *http.Request) {    if err := r.ParseForm(); err != nil {        fmt.Fprintf(w, "ParseForm() err: %v", err)        return    }    fmt.Fprintf(w, "POST request successful")    name := r.FormValue("name")    address := r.FormValue("address")
fmt.Fprintf(w, "Name = %s\n", name) fmt.Fprintf(w, "Address = %s\n", address)}
复制代码

不要忘记将新的表单处理程序路由添加到 main() 函数。


http.HandleFunc("/form", formHandler)
复制代码


最后的 server.go 文件如下:


package main
import ( "fmt" "log" "net/http")
func helloHandler(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/hello" { http.Error(w, "404 not found", http.StatusNotFound) return }
if r.Method != "GET" { http.Error(w, "Method is not supported", http.StatusNotFound) return }
fmt.Fprintf(w, "Hello!")}
func formHandler(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { fmt.Fprintf(w, "ParseForm() err: %v", err) return } fmt.Fprintf(w, "POST request successful\n") name := r.FormValue("name") address := r.FormValue("address")
fmt.Fprintf(w, "Name = %s\n", name) fmt.Fprintf(w, "Address = %s\n", address)}
func main() {
// http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) { // fmt.Fprintf(w, "Hello!") // })
fileServer := http.FileServer(http.Dir("./static")) http.Handle("/", fileServer) http.HandleFunc("/hello", helloHandler)
http.HandleFunc("/form", formHandler)
fmt.Printf("Starting server at port 8088\n")
if err := http.ListenAndServe(":8088", nil); err != nil { log.Fatal(err) }}
复制代码


表单处理程序测试


我们可以通过使用 go run server.go 启动服务器来测试表单。当服务器启动时,访问 http://localhost:8088/form.html。您应该看到两个输入字段和一个提交按钮。


填写完表格后,点击提交按钮。服务器应处理您的 POST 请求并在 http://localhost:8088/form 响应页面上向您显示结果,例如以下响应:

如果你看到上面的结果,你已经成功地创建了你的第一个 Golang 网络和文件服务器。恭喜!如果您想进一步探索 Golang Web 服务器,Golang HTTP 包文档中有很多很好的例子。


官方文档:Writing Web Applications


希望本文能对你有所帮助,如果喜欢本文,可以点个关注。


下一篇文章见!宇宙古今无有穷期,一生不过须臾,当思奋争。

发布于: 刚刚阅读数: 9
用户头像

宇宙古今无有穷期,一生不过须臾,当思奋争 2020-05-07 加入

🏆InfoQ写作平台-签约作者 🏆 混迹于江湖,江湖却没有我的影子 热爱技术,专注于后端全栈,轻易不换岗 拒绝内卷,工作于外企开发,弹性不加班 热衷分享,执着于阅读写作,佛系不水文 同名公众号:《宇宙之一粟》

评论

发布
暂无评论
如果利用 Go 创建一个 Web 应用_Go_宇宙之一粟_InfoQ写作社区