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

举报
宇宙之一粟 发表于 2023/04/25 20:39:55 2023/04/25
【摘要】 客户端/服务器假设你开发了一个使用 Go 语言编写的程序来管理你的照片库,这个程序可以在你的电脑上处理你的照片。你可能想与其他家庭成员分享这些照片,为此,你可以通过电子邮件发送包含所有照片的附件。但如果你拍了一万张照片,这种解决方案可能是不可行的。您可以将内容自动上传到您最喜爱的社交网络。如果您必须一次处理一张照片,该操作可能会变得非常耗时。另一种解决方案可能是将您的程序直接插入社交网络系...

客户端/服务器

假设你开发了一个使用 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

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

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

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。