一般来说,理解 HTTP 构建的网络应用,只要关注客户端(clinet)和服务端(server),两个端的交互来自客户端的 request,以及服务端的response。所谓的http服务器,主要在于如何接受客户端的 request,并向服务端返回response。
Http接收和响应来自客户端的HTTP请求,需要用到golang自带的net.http包,实现动态请求处理。Go语言内置的net/http包提供了HTTP客户端和服务端的实现。
在接受的过程中路由(router)十分重要,路由url到函数的映射,而这里的路由目的就是为了找到处理器函数(handler),函数将对来自客户端request进行处理,同时构建response返回至服务器。
一、路由路由就是url到函数的映射
route就是你访问一个页面的地址。router就是由一群地址组成的东西。
当访问/healthz路径时,会执行healthz函数
服务器端
简单来说,对于服务器,当接收到客户端发来的HTTP请求,会根据请求的URL,来找到相应的映射函数,然后执行该函数,并将函数的返回值发送给客户端。
静态资源服务器:url映射函数可以理解为一个文件读取 *** 作
动态资源服务器:url映射可以理解为从数据库读取 *** 作,或是数据处理
客户端路由的映射函数通常是进行一些DOM的显示和隐藏 *** 作。
二、HTTP请求的接收与处理流程1、客户端将请求发送到服务器(指定URL)。
2、服务器将请求指向到正确的处理器,然后由该处理器对请求进行处理。
3、处理器处理请求,执行必要的动作。
4、处理器将结果返回给客户端。
在理解以上概念后,就要进入http server的创建了。创建httpserver有两个步骤,首先是注册路由,接下来就是其次就是实例化一个server对象,开始监听来自客户端request。
注册路由通过这个包的http.HandleFunc函数,我们可一个注册一个请求处理器,该函数的第一个参数是请求路径的字符串,第二个参数即为处理请求的函数主体func(ResponseWriter, * Request) 类型的函数。
http.HandleFunc("/", httpAccessFunc)
http.Handle和http.HandleFunc区分
Go 网络编程:使用 Handler 和 HandlerFunc - 简书
简单的httpserverpackage main
import (
"io"
"log"
"net/http"
)
func main() {
http.HandleFunc("/healthz", healthz)
//handle定义请求访问该服务器里的/healthz路径,就有下面healthz去处理,healthz一般为健康检查
err := http.ListenAndServe(":80", nil)
if err != nil {
log.Fatal(err)
}
}
//定义handle处理函数,只要该healthz被调用,就会写入ok
func healthz(w http.ResponseWriter, request *http.Request) {
io.WriteString(w, "ok")
}
编写http server
要求:
1、接收客户端 request,并将 request 中带的 header 写入 response header
2、读取当前系统的环境变量中的 VERSION 配置,并写入 response header
3、Server 端记录访问日志包括客户端 IP,HTTP 返回码,输出到 server 端的标准输出
4、当访问 localhost/healthz 时,应返回 200
package main
import (
"fmt"
"log"
"net"
"net/http"
"os"
"strconv"
)
func main() {
HttpServerStart(8080)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
func HttpServerStart(port int) {
log.SetPrefix("Info:") //为每条日志文本前增加一个info:前缀
log.SetFlags(log.Ldate | log.Llongfile) //可以获取当前设置的选项,Ldate:输出当地时区的日期;Llongfile:输出长文件名+行号
http.HandleFunc("/", httpAccessFunc) //http.HandleFunc接收两个参数,一个是路由匹配的字符串,另外一个是 func(ResponseWriter, *Request) 类型的函数
http.HandleFunc("healthz", healthzFunc)
err := http.ListenAndServe(":"+strconv.Itoa(port), nil)
if err != nil {
log.Fatal(err) //输出日志后,调用os.Exit(1)退出程序
}
}
func healthzFunc(w http.ResponseWriter, r *http.Request) {
HealthzCode := "200"
w.Write([]byte(HealthzCode))
}
func httpAccessFunc(w http.ResponseWriter, r *http.Request) {
if len(r.Header) > 0 {
for k, v := range r.Header {
log.Printf("%s=%s", k, v[0])
//1. request header写入response header
w.Header().Set(k, v[0])
}
}
log.Printf("\n\n\n")
r.ParseForm() //解析所有请求数据,否则无法获取数据
if len(r.Form) > 0 {
for k, v := range r.Form {
log.Printf("%s=%s", k, v[0])
}
}
log.Printf("\n\n\n")
os.Setenv("VERSION", "JDK version 1.11.0") //设置环境值的值
//2. 获取环境变量"VERSION"
name := os.Getenv("VERSION")
log.Printf("VERSION Env: ", name)
log.Printf("\n\n\n")
//3.获取Client IP,并且打印出来
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
fmt.Println("err:", err)
}
if net.ParseIP(ip) != nil {
fmt.Println("ip ===>>%s\n", ip)
log.Println(ip)
}
fmt.Println("http Status Code ===>>%s\n", http.StatusOK)
log.Println(http.StatusOK)
//response响应
w.WriteHeader(http.StatusOK)
w.Write([]byte("Server Access,Success!"))
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)