HTTP,无连接协议(connection-less protocol),两次请求间一无所知,通过cookie实现数据持久化。
Header、Request和Cookie
支持客户端。Header、Request和Cookie
支持服务端。客户端与多路复用器交互(请求和响应);
多路复用器与不同处理器交互;
处理器与模板引擎、模型交互;
模板引擎与模板交互、模型与数据库交互。
package main
import (
"net/http"
)
func main() {
//”“,使用80端口
//nil,使用默认多路复用器DefaultServeMux
http.ListenAndServe("", nil)
}
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()
}
密码或信用卡等私密信息,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),负责对通信加密。
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")
}
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()
}
默认多路复用器未设置处理器时,返回404 HTTP响应。
//处理器定义
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
DefaultServeMux多路复用器是ServeMux(实现了Handler接口)的实例。
DefaultServeMux也是一个特殊的处理器,将请求URL重定向到不同处理器。
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()
}
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()
}
与处理器拥有相同行为的函数。
//处理器函数类型定义
//实现了Handler接口
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
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()
}
使用串联(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()
}
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,/匹配
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()
}
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 强制接收创建的证书