《Go Web 编程》之第3章 接收请求

《Go Web 编程》之第3章 接收请求

  • 第3章 接收请求
    • 3.1 net/http标准库
    • 3.2 Go构建服务器
      • 3.2.1 Go Web服务器
      • 3.2.2 通过HTTPS提供服务
    • 3.3 处理器和处理器函数
      • 3.3.1 处理请求
      • 3.3.2 使用多个处理器
      • 3.3.3 处理器函数
      • 3.3.4 串联处理器和处理器函数
      • 3.3.5 ServeMux和DefaultServeMux
      • 3.3.6 其它多路复用器
    • 3.4 使用HTTP/2

第3章 接收请求

3.1 net/http标准库

HTTP,无连接协议(connection-less protocol),两次请求间一无所知,通过cookie实现数据持久化。

  • Client、Response、Header、Request和Cookie支持客户端。
  • Server、ServeMux、Handler/HandlerFunc、ResponseWriter、Header、Request和Cookie支持服务端。

3.2 Go构建服务器

客户端与多路复用器交互(请求和响应);
多路复用器与不同处理器交互;
处理器与模板引擎、模型交互;
模板引擎与模板交互、模型与数据库交互。

3.2.1 Go Web服务器

  • simplest_server.go
package main

import (
	"net/http"
)

func main() {
	//”“,使用80端口
	//nil,使用默认多路复用器DefaultServeMux
	http.ListenAndServe("", nil)
}
  • configurable_server.go
package main

import (
	"net/http"
)

func main() {
	server := http.Server{
		Addr:    "127.0.0.1:8080",
		Handler: nil,
	}
	server.ListenAndServe()
}
type Server struct {
	Addr string
	Handler Handler
	TLSConfig *tls.Config
	ReadTimeout time.Duration		//读超时
	ReadHeaderTimeout time.Duration
	WriteTimeout time.Duration		//写超时
	IdleTimeout time.Duration
	MaxHeaderBytes int
	TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
	ConnState func(net.Conn, ConnState)
	ErrorLog *log.Logger	//错误日志记录器
	BaseContext func(net.Listener) context.Context
	ConnContext func(ctx context.Context, c net.Conn) context.Context
	inShutdown atomicBool
	disableKeepAlives int32 
	nextProtoOnce     sync.Once
	nextProtoErr      error
	mu         sync.Mutex
	listeners  map[*net.Listener]struct{}
	activeConn map[*conn]struct{}
	doneChan   chan struct{}
	onShutdown []func()
}

3.2.2 通过HTTPS提供服务

密码或信用卡等私密信息,HTTPS对通信进行加密和保护。
SSL(Secure Socket Layer,安全套接字层),通过公钥基础设施(Public Key Infrastructure,PKI)为通信双方数据加密和身份验证(SSL证书,存储在服务器,包含公钥及相关信息的数据文件)。
TLS(Transport Layer Security),传输层安全协议。
HTTPS = HTTP + SSL/TLS

(Certificate Authority)CA签发SSL证书,保证可靠性。
(1)客户端发送请求,服务器返回证书和响应;
(2)客户端确认证书真实性,生成随机密钥(random key);
(3)利用证书公钥对随机密钥加密,产生实际密钥(actual key,对称密钥symmetric key),负责对通信加密。

  • https_server.go
package main

import (
	"net/http"
)

func main() {
	server := http.Server{
		Addr:    "127.0.0.1:8080",
		Handler: nil,
	}
	//cert.pem,SSL证书
	//key.pem,服务器私钥
	server.ListenAndServeTLS("cert.pem", "key.pem")
}
  • gencert.go
package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"math/big"
	"net"
	"os"
	"time"
)

func main() {
	max := new(big.Int).Lsh(big.NewInt(1), 128)
	serialNumber, _ := rand.Int(rand.Reader, max)
	subject := pkix.Name{//专有名称(distinguished name)
		Organization:       []string{"Manning Publications Co."},
		OrganizationalUnit: []string{"Books"},
		CommonName:         "Go Web Programming",
	}

	template := x509.Certificate{
		SerialNumber: serialNumber,//证书序列号,CA分发的唯一号码
		Subject:      subject,
		NotBefore:    time.Now(),
		NotAfter:     time.Now().Add(365 * 24 * time.Hour),//有效期一年
		//用于服务器身份验证操作
		KeyUsage:     x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		IPAddresses:  []net.IP{net.ParseIP("127.0.0.1")},
	}

	//RSA私钥,里面含有公开访问的公钥(public key)
	pk, _ := rsa.GenerateKey(rand.Reader, 2048)

	//DER编码格式化的字节切片
	derBytes, _ := x509.CreateCertificate(rand.Reader, &template, &template, &pk.PublicKey, pk)
	
	//证书编码到文件中
	certOut, _ := os.Create("cert.pem")
	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	certOut.Close()
	
	//PEM编码将密钥编码到文件中
	keyOut, _ := os.Create("key.pem")
	pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(pk)})
	keyOut.Close()
}

3.3 处理器和处理器函数

默认多路复用器未设置处理器时,返回404 HTTP响应。

3.3.1 处理请求

//处理器定义
type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

DefaultServeMux多路复用器是ServeMux(实现了Handler接口)的实例。
DefaultServeMux也是一个特殊的处理器,将请求URL重定向到不同处理器。

  • handler_server.go
package main

import (
	"fmt"
	"net/http"
)

type MyHandler struct{}

func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello World!")
}

func main() {
	handler := MyHandler{}
	server := http.Server{
		Addr:    "127.0.0.1:8080",
		Handler: &handler,	//指定处理器
	}
	server.ListenAndServe()
}

3.3.2 使用多个处理器

  • multihandler_server.go
package main

import (
	"fmt"
	"net/http"
)

type HelloHandler struct{}

func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello!")
}

type WorldHandler struct{}

func (h *WorldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "World!")
}

func main() {
	hello := HelloHandler{}
	world := WorldHandler{}
	
	//未指定处理器,使用DefaultServeMux作为处理器
	server := http.Server{
		Addr: "127.0.0.1:8080",
	}

	//将处理器绑定至DefaultServeMux
	/*
	package http
	func Handle(pattern string, handler Handler) { 
		DefaultServeMux.Handle(pattern, handler) 
	}
	*/
	http.Handle("/hello", &hello)
	http.Handle("/world", &world)

	server.ListenAndServe()
}

3.3.3 处理器函数

与处理器拥有相同行为的函数。

//处理器函数类型定义
//实现了Handler接口
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
	f(w, r)
}
  • handlerfunc_server.go
package main

import (
	"fmt"
	"net/http"
)

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello!")
}

func world(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "World!")
}

func main() {
	server := http.Server{
		Addr: "127.0.0.1:8080",
	}
	/*
	package http
	func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
		DefaultServeMux.HandleFunc(pattern, handler)
	}
	
	func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
		if handler == nil {
			panic("http: nil handler")
		}
		mux.Handle(pattern, HandlerFunc(handler))
	}
	*/
	http.HandleFunc("/hello", hello)
	http.HandleFunc("/world", world)

	server.ListenAndServe()
}

3.3.4 串联处理器和处理器函数

使用串联(chaining)技术分隔代码中的横切关注点(cross-cutting,日志记录、安全检查和错误处理等操作)。
chain_handlerfunc.go

package main

import (
	"fmt"
	"net/http"
	"reflect"
	"runtime"
)

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello!")
}

func log(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		name := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
		fmt.Println("Handler function called - " + name)
		h(w, r)
	}
}

func main() {
	server := http.Server{
		Addr: "127.0.0.1:8080",
	}
	http.HandleFunc("/hello", log(hello))
	server.ListenAndServe()
}

串联多个函数让程序执行更多动作,管道处理(pipeline processing)。
chain_handler.go

package main

import (
	"fmt"
	"net/http"
)

type HelloHandler struct{}

func (h HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello!")
}

func log(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Printf("Handler called - %T\n", h)
		h.ServeHTTP(w, r)
	})
}

func protect(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// some code to make sure the user is authorized
		h.ServeHTTP(w, r)
	})
}

func main() {
	server := http.Server{
		Addr: "127.0.0.1:8080",
	}
	hello := HelloHandler{}
	http.Handle("/hello", protect(log(hello)))
	server.ListenAndServe()
}

3.3.5 ServeMux和DefaultServeMux

ServeMux,将请求URL重定向(映射)至相应处理器。

DefaultServeMux是ServeMux的实例,默认多路复用器。
最小惊讶|意外原则(The Principle of Least Surprise),设计时做合乎常理的事情,使事情的行为总是显而易见、始终如一并且合乎常理,比如门旁边的按钮与门有关。

(1)URL非/结尾,匹配完全相同的URL;
(2)URL以/结尾,前缀匹配即可。

/hello与/hello/不匹配,与/hello,/匹配
/hello/there与/hello/there/不匹配,与/hello/there,/hello//hello,/匹配

3.3.6 其它多路复用器

httprouter.go

package main

import (
	"fmt"
	"github.com/julienschmidt/httprouter"
	"net/http"
)

func hello(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintf(w, "hello, %s!\n", p.ByName("name"))
}

func main() {
	mux := httprouter.New()
	//绑定URL的GET方法
	//:name,具名参数(named parameter)
	mux.GET("/hello/:name", hello)

	server := http.Server{
		Addr:    "127.0.0.1:8080",
		Handler: mux,
	}
	server.ListenAndServe()
}

3.4 使用HTTP/2

package main

import (
	"fmt"
	"net/http"
)

type MyHandler struct{}

func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello World!")
}

func main() {
	handler := MyHandler{}
	server := http.Server{
		Addr:    "127.0.0.1:8080",
		Handler: &handler,
	}
	//http2.ConfigureServer(&server, &http2.Server{})
	server.ListenAndServeTLS("cert.pem", "key.pem")
}
curl -I --http2 --insecure https://localhost:8080/
curl --http2 --insecure https://localhost:8080/
curl --help
-d	发送数据
-I, --head	只显示头部	
-i,包含协议响应头
--http2 	使用HTTP2
--insecure	强制接收创建的证书

你可能感兴趣的:(Go,golang,ssl)