Go 语言入门很简单:HTTP 包

举报
宇宙之一粟 发表于 2022/10/31 19:21:23 2022/10/31
【摘要】 引言Go 语言提供功能丰富的 ​​net/http​​​,实现了基础的 HTTP 中的 ​​client​​​ 和 ​​server​​​ 功能。在这一篇​​文章​​也有介绍一个基础的 HelloWorld 应用。如果没看过,也可以使用下面的代码创建一个简易 HTTP 的 ​​server​​ 服务:package mainimport ( "log" "net/http")type H...

引言

Go 语言提供功能丰富的 ​​net/http​​​,实现了基础的 HTTP 中的 ​​client​​​ 和 ​​server​​​ 功能。在这一篇​​文章​​也有介绍一个基础的 HelloWorld 应用。

如果没看过,也可以使用下面的代码创建一个简易 HTTP 的 ​​server​​ 服务:

package main

import (
  "log"
  "net/http"
)

type Handler struct{}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

  _, err := w.Write([]byte("Welcome to my Website!"))
  if err != nil {
    log.Println(err)
  }
}

func main() {

  log.Println(http.ListenAndServe("127.0.0.1:8080", &Handler{}))
}

​http.ListenAndServe​​​ 的第一个参数是传入监听的地址,第二个参数是 ​​http.Handle​​​ 接口实现者。该接口需要 ​​ServeHTTP(w http.ResponseWriter, r *http.Request)​​ 函数。这个函数将处理我们服务器上的所有请求。

第一个终端上使用 ​​go run main.go​​ 运行该服务器:

$ go run main.go

然后打开另个一终端:

$ curl localhost:8080/
Welcome to my Website!

$ curl localhost:8080/hello
Welcome to my Website!

我们还可以配置服务器来处理特定的 URL,例如 ​​/hello​​:

package main

import (
  "log"
  "net/http"
)

type Handler struct{}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

  _, err := w.Write([]byte("Welcome to my Website!"))
  if err != nil {
    log.Println(err)
  }
}

func main() {

  http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
    _, err := w.Write([]byte("Hello, world!"))
    if err != nil {
      log.Println(err)
    }
  })

  log.Println(http.ListenAndServe("127.0.0.1:8080", nil))
}

运行另一个终端,能看到如下结果::

$ curl localhost:8080/hello
Hello, world!

$ curl localhost:8080/
404 page not found

它是如何工作的?当我们调用 ​​http.HandleFunc​​​ 时,路径和处理函数被添加到 ​​net/http.DefaultServeMux​​​ 结构中,即包含所有这些。当我们调用特定的 URL 时,​​net/http.DefaultServeMux​​ 用于查找特定的处理程序。如果未找到处理程序,将生成标准 404 响应。

标准路由对每个注册的 URL 实现唯一的纯 URL 比较。模式匹配,例如匹配 ​​/hello/{page} ​​之类的表达式,其中页面参数在多个调用之间可能不同,这对于标准路由器是不可能的。要实现这一点,我们需要自己实现模式匹配或使用路由器库之一。

自定义路由

我们可以使用任何其他路由器,例如 ​​gorilla/mux​​ :一个强大的 HTTP 路由器和 URL 匹配器,用于构建 Go web 服务器 🦍。目前已经在 Github 收获 16k 的 star,它支持模式匹配。

func main() {
  r := mux.NewRouter()
  r.HandleFunc("/products/{key}", ProductHandler)
  r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
  r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
  http.Handle("/", r)
}

接下来,在处理程序中,我们可以从 URL 中获取变量:

中间件

在标准 Web 服务中,不仅有处理程序的代码在每个请求上运行。还有一些通用代码执行一些通用工作——日志记录、统计信息抓取、授权检查等。这些通用代码称为中间件。

GO 标准库中没有明确的中间件实现。但是任何人都可以通过使用嵌套处理程序来实现类似的东西。让我们看一下日志中间件,它将每个请求的 URL 打印到控制台:

package main

import (
  "log"
  "net/http"
)

type LoggingMiddleware struct {
  handler http.Handler
}

func NewLoggingMiddleware(handler http.Handler) *LoggingMiddleware {
  return &LoggingMiddleware{
    handler: handler,
  }
}

func (l *LoggingMiddleware) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  log.Println(req.URL, "requested")

  l.handler.ServeHTTP(w, req)
}

type Handler struct{}

func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  _, err := w.Write([]byte("hello"))
  if err != nil {
    log.Println(err)
  }
}

func main() {
  log.Println(http.ListenAndServe(":9090", NewLoggingMiddleware(&Handler{})))
}
$ curl localhost:8080/
hello

$ curl localhost:8080/hello
hello

在对我们服务器的每个请求中,我们现在可以在控制台中看到以下数据:

$ go run main.go
2022/04/27 23:44:18 / requested
2022/04/27 23:44:23 /hello requested

很多游戏的 Go Web 库如 ​​echo​​​ 、​​gin​​ 可以显着地帮助实现中间件。此外,许多库已经涵盖了最流行的中间件任务。

HTTP客户端

在 ​​net/http​​ 包中有一个 Client 结构,它负责 HTTP 客户端请求:

package main

import (
  "fmt"
  "io/ioutil"
  "log"
  "net/http"
)

func main() {

  client := http.Client{}

  resp, err := client.Get("https://bing.com/")
  if err != nil {
    log.Fatal(err)
  }

  buf, err := ioutil.ReadAll(resp.Body)
  resp.Body.Close()
  if err != nil {
    log.Fatal(err)
  }

  fmt.Println(string(buf))
}

运行结果会返回该网页的内容:



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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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