前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go HTTP 编程 | 01 - 使用 http 包创建 Web 服务器

Go HTTP 编程 | 01 - 使用 http 包创建 Web 服务器

作者头像
RiemannHypothesis
发布2022-11-25 11:32:33
9040
发布2022-11-25 11:32:33
举报
文章被收录于专栏:ElixirElixir

一、Go 的 HTTP 标准库 net/http

Go 已经拥有成熟的 HTTP 标准库 net/http,即使不使用 Go 的 Web 框架如 Gin、Iris 等也可以快速的搭建起一个可以运行的 Web 服务,同时这个标准库可以对 Web 路由、静态文件、模板和cookie 等数据进行处理,事实上这些 Web 框架也都是基于 net/http 标准库来构建的。

使用 net/http 建立 Web 服务器

首先创建一个请求处理函数 sayHelloHandler,该函数接收一个 http.ResponseWriter 和 一个请求指针 *http.Request 作为参数,通过对请求中数据的提取之后写入指定的信息到 http.ResponseWriter 中。

在 main 函数中通过 http.HandleFunc 定义一个路由并将该路由与 sayHelloHandler 函数映射,然后通过 http.ListenAndServe 监听端口。

运行 main.go 文件,一个简单的 Web 服务器就运行起来了。

代码语言:javascript
复制
package main

// filename main.go

//noinspection ALL
import (
   "fmt"
   "log"
   "net/http"
   "strings"
)

//noinspection ALL
func main(){
   http.HandleFunc("/", sayHelloName)
   err := http.ListenAndServe(":9000", nil)

   if err != nil {
      log.Fatal("ListenAndServer: ", err)
   }
}

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

   r.ParseForm() // 解析参数,默认是不会解析的
   fmt.Println(r.Form) // 输出
   fmt.Println("path", r.URL.Path)
   fmt.Print("Scheme", r.URL.Scheme)
   fmt.Println(r.Form["url_long"])

   for k, v := range r.Form{
      fmt.Println("Key", k)
      fmt.Println("Val", strings.Join(v, ""))
   }

   fmt.Fprint(w, "Hello, Go HTTP")
}

在浏览器中输入 http://localhost:9000/

image.png
image.png

控制台打印出的详细信息

image.png
image.png

net/http 运行机制

net/http 运行流程:

  1. 创建 Listen Socket 监听指定端口,等待客户端请求
  2. Listen Socket 接收客户端请求,得到 Client Socket,服务端通过 Clent Socket 与客户端进行通信
  3. 处理客户端请求,首先从 Client Socket 读取 HTTP 请求的信息,包括请求头和请求体,然后交给相应的 handler 函数处理,handler 处理完成后将数据通过 Client Socket 写给客户端。
image.png
image.png

整个过程我们需要了解三个问题:

  • net/http 是如何监听端口的?
  • net/http 是如何接收客户端请求的?
  • net/http 是如何分配 handler 的?

查看源码,点击 main.go 文件中 http.ListenAndServe(":9000", nil)ListenAndServe 函数,来到源码,再次点击 3222 行的 ListenAndServe

image.png
image.png

再次点击 2968 行的 Serve 函数:

image.png
image.png
image.png
image.png

Serve(l net.Listener) 函数就是处理接收客户端的请求信息。该函数中的 for 循环首先通过 net.Listener 接收请求 rw, err := l.Accept()for 循环之后又创建了一个 Conn,最后单独开了一个 goroutine go c.serve(connCtx);用户的每一次请求都是在一个单独的 goroutine 中执行的,不会相互影响。

点击 go c.serve(connCtx) 中的 serve(connCtx) 方法,在该方法中的第 1891 行通过 c.readRequest(ctx) 来解析请求:

image.png
image.png

然后在第 1966 行,根据请求解析结果通过 serverHandler{c.server}.ServeHTTP(w, w.req) 分配了一个 handler

image.png
image.png

点击查看 ServeHTTP 源码:

image.png
image.png

这里获取了一个 handler,调用 ListenAndServe 函数的时候传递的参数为 nil,因此这里默认分配了一个 DefaultServeMux 作为 handler。其实 DefaultServeMux 就是一个路由器,它用来匹配 URL 跳转到其响应的 handler 函数。

上述代码中 http.HandleFunc("/", sayHelloName) 就已经定义了路由规则,当请求为 / 时,路由就会转到 sayHelloName 方法,DefaultServeMux 就会调用 ServeHTTP 方法,则这个方法内部其实就是调用 sayHelloName 方法,然后将返回结果写入到 response 中,最后返回给客户端。

整个处理流程如下:

image.png
image.png
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-11-07,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Go 的 HTTP 标准库 net/http
    • 使用 net/http 建立 Web 服务器
      • net/http 运行机制
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档