Golang 搭建一个基础的 web 服务:Hello World

1. 源代码

package main

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

func sayhelloName(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()       //解析参数,默认是不会解析的
	fmt.Println(r.Form) //这些信息是输出到服务器端的打印信息
	fmt.Println("path", r.URL.Path)
	fmt.Println("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.Fprintf(w, "Hello World!") //这个写入到w的是输出到客户端的
}

func main() {
	http.HandleFunc("/", sayhelloName)       //设置访问的路由
	err := http.ListenAndServe(":9090", nil) //设置监听的端口
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

2. 代码解析

2.1 http.HandleFunc

在 Go 语言的 net/http 包中,HandleFunc 是一个用于注册处理 HTTP 请求的函数。它将一个 URL 路径和一个处理该路径的函数关联起来。当 HTTP 服务器收到一个请求时,它将根据请求的 URL 路径找到对应的处理函数,并调用该函数处理请求。

HandleFunc 的原型如下:

func HandleFunc(pattern string, handler func(ResponseWriter, *Request))

其中,pattern 是一个字符串,表示 URL 路径的模式;handler 是一个函数,它接受两个参数:一个 ResponseWriter 接口和一个指向 Request 结构的指针。ResponseWriter 接口用于向客户端发送 HTTP 响应,Request 结构包含了客户端的 HTTP 请求信息。

在上面的例子中,我们打印了request 结构体的信息,同时将Hello World!写入到response 当中,在服务终端的打印里面,答应结果如下。

map[]
path /
scheme 
[]
map[]
path /favicon.ico
scheme 
[]

在客户端浏览器当中的解析接过如图,我们在请求当中访问本地:127.0.0.1:9090路径即可。
在这里插入图片描述

2.2 http.Request

http.Request 是 Go 语言 net/http 包中的一个结构体,用于表示一个 HTTP 请求。它包含了客户端发送的请求信息,如 HTTP 方法、URL、头部信息、请求正文等。以下是 http.Request 结构体的定义:

type Request struct {
    Method string
    URL *url.URL
    Proto      string // "HTTP/1.0"
    ProtoMajor int    // 1
    ProtoMinor int    // 0
    Header Header
    Body io.ReadCloser
    GetBody func() (io.ReadCloser, error)
    ContentLength int64
    TransferEncoding []string
    Close bool
    Host string
    Form url.Values
    PostForm url.Values
    MultipartForm *multipart.Form
    Trailer Header
    RemoteAddr string
    RequestURI string
    TLS *tls.ConnectionState
    Cancel <-chan struct{}
    Response *Response
    ctx context.Context
}

结构体当中的主要字段如下:
Method: 请求的 HTTP 方法(如 “GET”、“POST” 等)。
URL: 请求的 URL,为 *url.URL 类型。
Proto: 请求使用的 HTTP 协议版本,如 “HTTP/1.1”。
ProtoMajor 和 ProtoMinor: 分别表示 HTTP 协议的主版本号和次版本号。
Header: 请求的头部信息,为 http.Header 类型,存储键值对形式的头部信息。
Body: 请求的正文,为 io.ReadCloser 类型。它是一个可读的数据流,可以用于读取请求的正文数据。
ContentLength: 请求正文的长度,为 int64 类型。
TransferEncoding: 请求的传输编码,为字符串切片类型。
Host: 请求的主机名,包括域名和端口号。
Form: 请求的表单数据,为 url.Values 类型。用于解析 “application/x-www-form-urlencoded” 类型的表单数据。
PostForm: 请求的 POST 表单数据,为 url.Values 类型。用于解析 “application/x-www-form-urlencoded” 类型的 POST 表单数据。
MultipartForm: 请求的多部分表单数据,为 *multipart.Form 类型。用于解析 “multipart/form-data” 类型的表单数据。
Trailer: 请求的尾部头信息,为 http.Header 类型。用于解析 “trailer” 头部信息。
RemoteAddr: 请求的远程地址,包括 IP 地址和端口号。
RequestURI: 请求的原始 URL 路径。
TLS: 请求的 TLS 连接状态,为 *tls.ConnectionState 类型。如果请求是 HTTPS 请求,则此字段包含 TLS 连接的详细信息。
ctx: 请求的上下文,为 context.Context 类型。用于在处理请求时传递元数据和超时/取消信号。
通常情况下,你不需要直接创建 http.Request 结构体的实例,而是通过处理函数的参数接收到一个指向 http.Request 结构体的指针。你可以通过这个指针访问和操作请求的各种信息。

2.3 http.ResponseWriter

http.ResponseWriter 是 Go 语言 net/http 包中的一个接口,用于表示 HTTP 响应的写入器。在处理 HTTP 请求时,你可以使用 http.ResponseWriter 向客户端发送 HTTP 响应,包括状态码、头部信息和响应正文。以下是 http.ResponseWriter 接口的定义:

type ResponseWriter interface {
    Header() Header
    Write([]byte) (int, error)
    WriteHeader(statusCode int)
}

http.ResponseWriter 接口包含三个方法,以下是这些方法的简要说明:

Header() Header: 返回一个表示响应头部信息的 http.Header 类型。你可以通过这个方法获取到一个 http.Header 实例,并修改它以设置响应的头部信息。例如,设置响应的内容类型:

w.Header().Set("Content-Type", "application/json")

Write([]byte) (int, error): 将字节切片写入响应正文。这个方法接受一个字节切片作为参数,并将其写入响应正文。它返回写入的字节数和可能遇到的错误。例如,向客户端发送一个简单的响应:

response := []byte("Hello, world!")
w.Write(response)
WriteHeader(statusCode int): 

设置响应的状态码。这个方法接受一个整数作为参数,并将其设置为响应的状态码。注意,你应该在写入响应正文之前调用此方法。例如,设置一个 404 Not Found 响应:

w.WriteHeader(http.StatusNotFound)

通常情况下,你不需要自己实现 http.ResponseWriter 接口。当你编写一个处理 HTTP 请求的函数时,你会接收到一个指向 http.ResponseWriter 接口的指针。你可以通过这个指针调用上述方法来发送 HTTP 响应。例如:

func myHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/plain")
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("Hello, world!"))
}

2.4 http.ListenAndServe

http.ListenAndServe 是 Go 语言 net/http 包中的一个函数,用于启动一个 HTTP 服务器并监听指定的地址和端口。它会接收客户端的 HTTP 请求,根据请求的 URL 路径找到对应的处理函数,并调用该函数处理请求。以下是 http.ListenAndServe 函数的原型:

func ListenAndServe(addr string, handler Handler) error

http.ListenAndServe 接受两个参数:

addr (string): 要监听的地址和端口,格式为 “host:port”。例如,“:8080” 表示监听所有可用的网络接口上的 8080 端口。
handler (Handler): 用于处理 HTTP 请求的处理器。Handler 是一个接口,你可以实现该接口来处理请求。通常情况下,你可以使用 http.DefaultServeMux(默认的多路复用器)处理请求,它会根据请求的 URL 路径调用已注册的处理函数。要使用 http.DefaultServeMux,只需将 handler 参数设置为 nil 即可。
http.ListenAndServe 函数返回一个错误,如果启动 HTTP 服务器失败,它会返回一个描述错误的 error 类型。

3.基础知识

3.1 HTTP 协议

HTTP(HyperText Transfer Protocol,超文本传输协议)是一种用于传输超文本(如 HTML、CSS、JavaScript 等)的应用层协议。它是互联网上最广泛使用的协议,构成了万维网(World Wide Web)的基础。HTTP 协议基于请求-响应模型,客户端(如浏览器)通过发送 HTTP 请求来获取资源,服务器接收并处理请求后返回一个 HTTP 响应。

HTTP 协议的主要特点包括:

无状态:HTTP 协议本身不维护客户端和服务器之间的状态信息。这意味着每个请求都是独立的,服务器无法识别连续的请求之间的关系。为了实现状态管理,可以使用 Cookie 和 Session 等技术。

简单快速:HTTP 协议简单易懂,客户端和服务器之间的通信过程简洁高效。

可扩展:HTTP 协议允许自定义请求方法、头部字段和状态码,这使得它具有很好的扩展性。

灵活:HTTP 协议允许传输任何类型的数据,通过 Content-Type 头部字段指定数据类型。

HTTP 协议包括一系列请求方法,如 GET、POST、PUT、DELETE 等,用于指定请求的类型和操作。HTTP 请求和响应都包含头部信息(Header)和正文(Body)。头部信息用于描述请求或响应的元数据,如内容类型、编码方式、认证信息等。正文包含实际的数据,如 HTML 文档、JSON 数据等。

HTTP 协议有多个版本,其中最常用的是 HTTP/1.1 和 HTTP/2。HTTP/1.1 是目前最广泛使用的版本,它引入了持久连接、管道化请求等特性以提高性能。HTTP/2 是最新的版本,它采用了二进制帧、多路复用等技术,进一步提高了传输效率和性能。此外,还有 HTTPS 协议,它是在 HTTP 协议的基础上加入了 SSL/TLS 加密层,用于保护数据的安全性和隐私性。

3.2 POST 方法

HTTP 协议中的 POST 方法是一种用于提交数据到服务器的方法。POST 请求通常用于创建或更新资源,如提交表单、上传文件等。与 GET 方法相比,POST 方法具有以下特点:

非安全:POST 方法会对服务器上的资源产生影响,如创建新资源或修改现有资源。因此,它不是安全的。

非幂等:多次执行相同的 POST 请求可能导致不同的结果。例如,多次提交相同的表单可能导致多个资源被创建。

不可缓存:根据 HTTP 规范,POST 请求的响应不应被客户端(如浏览器)缓存。

请求参数:POST 请求的参数通常通过请求正文(Body)传递,而不是 URL 的查询字符串。这使得 POST 请求能够发送更大的数据量,并提供更好的隐私保护。

以下是一个简单的 POST 请求示例:

POST /submit HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 13

name=test&age=20

在这个示例中,客户端向服务器发送了一个 POST 请求,请求提交数据到 “/submit” 路径。请求正文包含了两个参数:name 和 age。服务器接收到请求后,会根据请求的路径和正文数据处理请求(例如,将数据存储到数据库),并返回一个响应给客户端。

3.3 GET 方法

HTTP 协议中的 GET 方法是一种用于请求和获取指定资源的方法。GET 请求通常用于从服务器检索信息,而不是修改或创建资源。GET 方法具有以下特点:

安全:GET 方法是安全的,因为它不会对服务器上的资源产生任何影响。换句话说,GET 请求仅用于读取数据,而不是修改数据。

幂等:多次执行相同的 GET 请求,其结果也应该相同。无论执行一次还是多次,服务器上的资源状态都不会发生变化。

可缓存:GET 请求的响应可以被客户端(如浏览器)缓存,以便将来重用。这可以提高性能,减少服务器的负载。

请求参数:GET 请求的参数通常通过 URL 的查询字符串传递。查询字符串是 URL 中 “?” 符号后面的部分,包含一系列键值对,表示请求参数。例如:http://example.com/search?q=keyword

以下是一个简单的 GET 请求示例:

GET /search?q=keyword HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Accept: text/html

在这个示例中,客户端向服务器发送了一个 GET 请求,请求获取 “/search” 路径下的资源,并通过查询字符串传递了一个名为 “q” 的参数,值为 “keyword”。服务器接收到请求后,会根据请求的路径和参数找到对应的资源,并将其作为响应返回给客户端。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值