发布于 

go web部分 | 笔记整理!

Go web部分 | 笔记整理!

go web部分

Server

1
2
3
4
5
6
7
8
// handler func(ResponseWriter, *Request))
func handler(resp http.ResponseWriter, req *http.Request) {
fmt.Fprintf(resp, "hello world! url: %s", req.URL.Path)
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}

1. HandleFunc

1
2
3
4
5
6
// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // slice of entries sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}

type muxEntry struct {
h Handler
pattern string
}

// NewServeMux allocates and returns a new ServeMux.
func NewServeMux() *ServeMux { return new(ServeMux) }

// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux

var defaultServeMux ServeMux
1
2
3
4
5
6
7
// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()

if pattern == "" {
panic("http: invalid pattern")
}
if handler == nil {
panic("http: nil handler")
}
if _, exist := mux.m[pattern]; exist {
panic("http: multiple registrations for " + pattern)
}

if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
e := muxEntry{h: handler, pattern: pattern}
mux.m[pattern] = e
if pattern[len(pattern)-1] == '/' {
mux.es = appendSorted(mux.es, e)
}

if pattern[0] != '/' {
mux.hosts = true
}
}

2. ListenAndServe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// ListenAndServe listens on the TCP network address addr and then calls
// Serve with handler to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// The handler is typically nil, in which case the DefaultServeMux is used.
//
// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
// --.>补充一下https部分
// ListenAndServeTLS acts identically to ListenAndServe, except that it
// expects HTTPS connections. Additionally, files containing a certificate and
// matching private key for the server must be provided. If the certificate
// is signed by a certificate authority, the certFile should be the concatenation
// of the server's certificate, any intermediates, and the CA's certificate.
func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServeTLS(certFile, keyFile)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
type Server struct {
Addr string
Handler Handler
DisableGeneralOptionsHandler bool
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 atomic.Bool
disableKeepAlives atomic.Bool
nextProtoOnce sync.Once
nextProtoErr error
mu sync.Mutex
listeners map[*net.Listener]struct{}
activeConn map[*conn]struct{}
onShutdown []func()
listenerGroup sync.WaitGroup
}
A Server defines parameters for running an HTTP server. The zero value for Server is a valid configuration.
Methods on (*Server):
newConn(rwc net.Conn) *conn
maxHeaderBytes() int
initialReadLimitSize() int64
tlsHandshakeTimeout() time.Duration
Close() error
Shutdown(ctx context.Context) error
RegisterOnShutdown(f func())
closeIdleConns() bool
closeListenersLocked() error
ListenAndServe() error
shouldConfigureHTTP2ForServe() bool
Serve(l net.Listener) error
ServeTLS(l net.Listener, certFile string, keyFile string) error
trackListener(ln *net.Listener, add bool) bool
trackConn(c *conn, add bool)
idleTimeout() time.Duration
readHeaderTimeout() time.Duration
doKeepAlives() bool
shuttingDown() bool
SetKeepAlivesEnabled(v bool)
logf(format string, args ...any)
ListenAndServeTLS(certFile string, keyFile string) error
setupHTTP2_ServeTLS() error
setupHTTP2_Serve() error
onceSetNextProtoDefaults_Serve()
onceSetNextProtoDefaults()
ExportAllConnsIdle() bool
ExportAllConnsByState() map[ConnState]int
1
2
3
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}

模拟实现一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// handler func(ResponseWriter, *Request))
type Myhander struct {
}

func (my *Myhander) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
fmt.Fprintf(resp, "hello world! url: %s", req.URL.Path)
}
func main() {
//http.HandleFunc("/", handler)
//http.ListenAndServe(":8080", nil)
myhander := Myhander{}
server := &http.Server{Addr: ":8080", Handler: &myhander}
server.ListenAndServe()
}

Dir

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// A Dir implements FileSystem using the native file system restricted to a
// specific directory tree.
//
// While the FileSystem.Open method takes '/'-separated paths, a Dir's string
// value is a filename on the native file system, not a URL, so it is separated
// by filepath.Separator, which isn't necessarily '/'.
//
// Note that Dir could expose sensitive files and directories. Dir will follow
// symlinks pointing out of the directory tree, which can be especially dangerous
// if serving from a directory in which users are able to create arbitrary symlinks.
// Dir will also allow access to files and directories starting with a period,
// which could expose sensitive directories like .git or sensitive files like
// .htpasswd. To exclude files with a leading period, remove the files/directories
// from the server or create a custom FileSystem implementation.
//
// An empty Dir is treated as ".".
type Dir string

FileServer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"fmt"
"net/http"
)

func main() {
mux := http.NewServeMux()
file := http.FileServer(http.Dir("/public"))
mux.Handle("/static/",http.StripPrefix("/static",file))

mux.HandleFunc("/",index)

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

// 处理函数
func index(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer,"hello world! url %s",request.URL)
}

2. FileServer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// FileServer returns a handler that serves HTTP requests
// with the contents of the file system rooted at root.
//
// As a special case, the returned file server redirects any request
// ending in "/index.html" to the same path, without the final
// "index.html".
//
// To use the operating system's file system implementation,
// use http.Dir:
//
// http.Handle("/", http.FileServer(http.Dir("/tmp")))
//
// To use an fs.FS implementation, use http.FS to convert it:
//
// http.Handle("/", http.FileServer(http.FS(fsys)))
func FileServer(root FileSystem) Handler {
return &fileHandler{root}
}
1
2
3
type fileHandler struct {
root FileSystem
}
1
2
3
4
5
6
7
8
9
10
// A FileSystem implements access to a collection of named files.
// The elements in a file path are separated by slash ('/', U+002F)
// characters, regardless of host operating system convention.
// See the FileServer function to convert a FileSystem to a Handler.
//
// This interface predates the fs.FS interface, which can be used instead:
// the FS adapter function converts an fs.FS to a FileSystem.
type FileSystem interface {
Open(name string) (File, error)
}
1
2
3
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
1
2
3
4
5
6
7
8
func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
upath := r.URL.Path
if !strings.HasPrefix(upath, "/") {
upath = "/" + upath
r.URL.Path = upath
}
serveFile(w, r, f.root, path.Clean(upath), true)
}

index

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 处理函数
func index(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer,"hello world! url %s",request.URL)
//刚开始的时候
files := []string{
"templates/layout.html",
"templates/navbar.html",
"templates/index.html",
}
templates := template.Must(template.ParseFiles(files...))
if threads, err := data.Threads(); err == nil {
templates.ExecuteTemplate(writer, "layout", threads)
}
}

1. 添加cookie信息

设置cookie信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 处理cookie
func authenticate(w http.ResponseWriter, r *http.Request) {
// 基本逻辑是 解析请求
// 1. 如果认证信息ok 存储cookie 并跳转到主页
// 2. 如果认证信息file,直接跳转登录
r.ParseForm()
user, _ := data.UserByEmail(r.PostFormValue("email"))
if user.Password == data.Encrypt(r.PostFormValue("password")) {
session, _ := user.CreateSession()
cookie := http.Cookie{
Name: "this is a cookie",
Value: session.Uuid,
HttpOnly: true, // 只能通过http/https进行访问
}
//func SetCookie(w ResponseWriter, cookie *Cookie)
http.SetCookie(w, &cookie)
http.Redirect(w, r, "/", 302)
} else {
http.Redirect(w, r, "/login", 302)
}
}

验证cookie信息

1
2
3
4
5
6
7
8
9
10
func session(w http.ResponseWriter, r *http.Request) (see data.Session, err error) {
cookie, err := r.Cookie("this is a cookie")
if err == nil {
see = data.Session{Uuid: cookie.Value}
if ok, _ := see.Check(); !ok {
err = errors.New("Invalid Session!")
}
}
return
}

2. 处理优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func index(writer http.ResponseWriter, request *http.Request) {
// 优化之后
threads, err := data.Threads()
if err == nil {
_, err := session(writer, request)
public_temp_files:=[]string{
"templates/layout.html",
"templates/public.navbar.html",
"templates/index.html",
}
private_temp_files:=[]string{
"templates/layout.html",
"templates/priavte.navbar.html",
"templates/index.html",
}
var templates *template.Template
if err!=nil{
templates=template.Must(template.ParseFiles(public_temp_files...))
}else{
templates=template.Must(template.ParseFiles(private_temp_files...))
}
templates.ExecuteTemplate(writer,"layout",threads)
}
}

3. 继续抽离

1
2
3
4
5
6
7
8
9
// 继续优化
func generateHTML(w http.ResponseWriter, data interface{}, fn ...string) {
var files []string
for _, file := range fn {
files = append(files, fmt.Sprintf("tempplate/%s.html", file))
}
templates := template.Must(template.ParseFiles(files...))
templates.ExecuteTemplate(w, "layout", data)
}
1
2
3
4
5
6
7
8
9
10
11
12
// 处理函数
func index(writer http.ResponseWriter, request *http.Request) {
threads, err := data.Threads()
if err == nil {
_, err := session(writer, request)
if err != nil {
generateHTML(writer, threads, "layout", "public.navbar", "index")
} else {
generateHTML(writer, threads, "layout", "private.navbar", "index")
}
}
}