Go HTTP 编程(三):HTTP/HTTPS 请求处理

处理 HTTP 请求

服务端实现

使用 net/http 包提供的 http.ListenAndServe() 方法,可以开启一个 HTTP 服务器,并且在指定的 IP 地址和端口上监听客户端请求,该方法的原型如下:

func ListenAndServe(addr string, handler Handler) error

该方法有两个参数:第一个参数 addr 表示监听的 IP 地址及端口号;第二个参数表示服务端对应的处理程序,通常为空,意味着将调用 http.DefaultServeMux 进行处理,而服务端编写的业务逻辑处理程序 http.Handle() 或 http.HandleFunc() 默认会被注入到 http.DefaultServeMux 中。

下面我们按照上述思路实现一个最基本的 HTTP 服务器 server.go

package main

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

func main() {
    http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
        params := request.URL.Query();
        fmt.Fprintf(writer, "你好, %s", params.Get("name"))
    })
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatalf("启动 HTTP 服务器失败: %v", err)
    }
}

在这段代码中,我们通过 http.HandleFunc 方法定义了一个 /hello 路由及对应处理程序,在这个处理程序中我们会返回一个欢迎字符串,其中还引用了客户端传递过来的请求参数。然后通过 http.ListenAndServe 方法启动 HTTP 服务器,监听本地 IP 的 8080 端口,当客户端请求 http://127.0.0.1:8080/hello URL 时 HTTP 服务器会将其转发给默认的 http.DefaultServeMux 处理,这里最终会调用 http.HandleFunc 方法定义的处理器处理请求返回响应。

客户端请求

我们将前面教程实现的 HTTP 客户端示例代码 client.go 中的请求地址调整如下:

req, err := http.NewRequest("GET", "http://127.0.0.1:8080/hello?name=学院君", nil)

接下来,启动 HTTP 服务器:

go run server.go

然后新开一个 Terminal 窗口执行客户端调用代码:

HTTP请求处理

打印出了预期结果,说明 HTTP 服务器可以正常提供服务。

处理 HTTPS 请求

服务端逻辑

net/http 包还提供 http.ListenAndServeTLS() 方法,用于处理 HTTPS 连接请求:

func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error

ListenAndServeTLS() 和 ListenAndServe() 的行为一致,区别在于前者只处理 HTTPS 请求。要正确处理 HTTPS 请求,服务器上必须存在 SSL 证书和与之匹配的私钥相关文件,比如 certFile 对应 SSL 证书文件存放路径,keyFile 对应证书私钥文件路径。如果证书是由证书颁发机构签署的,certFile 参数指定的路径必须是存放在服务器上的经由 CA 认证过的 SSL 证书。

通过 OpenSSL 生成自签名证书

这里我们在本地演示 HTTPS 请求的处理,可以通过 OpenSSL 工具生成自签名证书:

# Generate CA private key 
openssl genrsa -out ca.key 2048 
# Generate CSR 
openssl req -new -key ca.key -out ca.csr
# Generate Self Signed certificate(CA 根证书)
openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt

这些文件都保存到 HTTPS 服务器代码所在目录:

HTTPS服务端目录结构

服务端代码

开启 HTTPS 监听服务也很简单,除了调用方法调整为 http.ListenAndServeTLS 并传入上面生成的 SSL 证书和私钥文件外,其它都和 HTTP 服务器一样,我们在 https 目录下新建 server.go 编写对应代码:

package main

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

func main() {
    http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
        params := request.URL.Query();
        fmt.Fprintf(writer, "你好, %s", params.Get("name"))
    })
    err := http.ListenAndServeTLS(":8443", "./ca.crt", "./ca.key",nil)
    if err != nil {
        log.Fatalf("启动 HTTPS 服务器失败: %v", err)
    }
}

然后启动这个 HTTPS 服务器:

go run server.php

客户端请求

接下来,我们在 https 目录下创建客户端调用代码 client.go

package main

import (
    "crypto/tls"
    "fmt"
    "io"
    "net/http"
    "os"
)

func main() {
    req, err := http.NewRequest("GET", "https://127.0.0.1:8443/hello?name=学院君", nil)
    if err != nil {
        fmt.Printf("请求初始化失败:%v", err)
        return
    }

    // 设置跳过不安全的 HTTPS
    tls11Transport := &http.Transport{
        MaxIdleConnsPerHost: 10,
        TLSClientConfig: &tls.Config{
            MaxVersion: tls.VersionTLS11,
            InsecureSkipVerify: true,
        },
    }

    client := &http.Client{
        Transport: tls11Transport,
    }

    resp, err := client.Do(req)
    if err != nil {
        fmt.Printf("客户端发起请求失败:%v", err)
        return
    }

    defer resp.Body.Close()
    io.Copy(os.Stdout, resp.Body)
}

这里,我们将请求 URL 调整为 HTTPS 协议,并且自定义了客户端实例的 Transport(更多底层细节可以参考上篇教程介绍)来跳过不安全的 HTTPS 连接验证。运行客户端代码,打印结果如下:

HTTPS请求处理

说明 HTTPS 请求成功。

当然以上 HTTP 服务和 HTTPS 服务通过浏览器访问也是可以的:

通过浏览器访问 HTTPS 服务

猜你喜欢

转载自blog.csdn.net/wxy_csdn_world/article/details/107444954