参见:
下载包 设置代理
妈的,下载包有时能下,有时候就卡住。
手动安装包
https://golang.org/pkg/net/http/
几个官方的例子,拿来练习一下,wc, 体会到了 go http 包的强大之处:
下面是一些例子,来主要讲解下面的几个函数
FileServer
FileServer (DotFileHiding)
FileServer (StripPrefix)
Get
Handle
HandleFunc
Hijacker
ListenAndServe
ListenAndServeTLS
NotFoundHandler
ResponseWriter (Trailers)
ServeMux.Handle
Server.Shutdown
StripPrefix
主体结构是:
func main(){
FileServer()
...
}
我把每个函数的例子,封装为一个函数 然后放在 main 函数里面执行一下。main 都是重复的,所以就不贴代码了。(联系 采用 subline,炒鸡方便)
-
FileServer
func FileServer(root FileSystem) Handler
这个函数也是很牛逼, 主要是可以把文件路径映射为 url 路由。
https://golang.org/pkg/net/http/#FileServer
实现原理:
https://shockerli.net/post/golang-pkg-http-file-server/
使用 FileSystem 接口 root 提供文件访问服务的 HTTP 处理器。可以方便的实现静态文件服务器
func FileServer(){
http.ListenAndServe(":8081", http.FileServer(http.Dir("F:/go/")))
}
运行效果:
上面是个简单的 可以展示文件目录的功能,go 底层,帮我们实现了 文件读取和展示。
支持子目录路径
只是比上面多了个 自定义路由前缀
http.StripPrefix() 方法配合 http.Handle() 或 http.HandleFunc() 可以实现带路由前缀的文件服务。
func FileServer(){
//
// http.ListenAndServe(":8081", http.FileServer(http.Dir("F:/go/")))
http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("F:/go/"))))
http.ListenAndServe(":8082", nil)
}
运行效果:
-
Handle
func Handle(pattern string, handler Handler)
路由匹配处理函数, 要实现 Handler 接口的 ServeHTTP(w http.ResponseWriter, r *http.Request) 方法
package main
import (
"fmt"
"log"
"net/http"
"sync"
)
type countHandler struct {
mu sync.Mutex // guards n
n int
}
func (h *countHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.mu.Lock()
defer h.mu.Unlock()
h.n++
fmt.Fprintf(w, "count is %d\n", h.n)
}
func main() {
http.Handle("/count", new(countHandler))
log.Fatal(http.ListenAndServe(":8080", nil))
}
-
HandleFunc
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
和 Handle 几乎一样,唯一不同的是参数不一样,这个是自己定义一个
xx(w http.ResponseWriter, r *http.Request) 这样的函数,儿不必叫 ServeHTTP 名字,因为 HandleFunc 函数第二个参数是 直接一个函数类型,二不是 有ServeHTTP 函数的 Handler 接口类型
func simple_server(){
http.HandleFunc("/my_name", name_haddler)
http.HandleFunc("/url", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h1>Hello, %q</h1>", html.EscapeString(r.URL.Path))
})
http.ListenAndServe(":8080", nil)
}
func name_haddler(w http.ResponseWriter, r *http.Request){
fmt.Fprintf(w, "<h1>hello yxl</h1>")
}
-
ListenAndServe
func ListenAndServe(addr string, handler Handler) error
第二个参数通常为 nil, 在这种情况下,使用DefaultServeMux。
func simple_server(){
http.HandleFunc("/my_name", name_haddler)
http.HandleFunc("/url", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h1>Hello, %q</h1>", html.EscapeString(r.URL.Path))
})
http.ListenAndServe(":8080", nil)
}
func name_haddler(w http.ResponseWriter, r *http.Request){
fmt.Fprintf(w, "<h1>hello yxl</h1>")
}
-
ListenAndServeTLS
func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error
ListenAndServe HTTPS 版本
-
NotFoundHandler
404 对应的处理
func NotFoundHandler() Handler
func NotFoundHandler(){
// 404 对应的处理
mux.Handle("/resources", http.NotFoundHandler())
}
-
ResponseWriter
一个接口
定义源码如下:
<pre style="font-family: Menlo, monospace; font-size: 0.875rem; line-height: 1.4; overflow-x: auto; margin: 1.25rem; background: rgb(239, 239, 239); padding: 0.625rem; border-radius: 0.3125rem; color: rgb(62, 64, 66); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">type ResponseWriter interface {
// Header returns the header map that will be sent by
// WriteHeader. The Header map also is the mechanism with which
// Handlers can set HTTP trailers.
//
// Changing the header map after a call to WriteHeader (or
// Write) has no effect unless the modified headers are
// trailers.
//
// There are two ways to set Trailers. The preferred way is to
// predeclare in the headers which trailers you will later
// send by setting the "Trailer" header to the names of the
// trailer keys which will come later. In this case, those
// keys of the Header map are treated as if they were
// trailers. See the example. The second way, for trailer
// keys not known to the Handler until after the first Write,
// is to prefix the Header map keys with the TrailerPrefix
// constant value. See TrailerPrefix.
//
// To suppress automatic response headers (such as "Date"), set
// their value to nil.
Header() [Header](https://golang.org/pkg/net/http/#Header)
// Write writes the data to the connection as part of an HTTP reply.
//
// If WriteHeader has not yet been called, Write calls
// WriteHeader(http.StatusOK) before writing the data. If the Header
// does not contain a Content-Type line, Write adds a Content-Type set
// to the result of passing the initial 512 bytes of written data to
// DetectContentType. Additionally, if the total size of all written
// data is under a few KB and there are no Flush calls, the
// Content-Length header is added automatically.
//
// Depending on the HTTP protocol version and the client, calling
// Write or WriteHeader may prevent future reads on the
// Request.Body. For HTTP/1.x requests, handlers should read any
// needed request body data before writing the response. Once the
// headers have been flushed (due to either an explicit Flusher.Flush
// call or writing enough data to trigger a flush), the request body
// may be unavailable. For HTTP/2 requests, the Go HTTP server permits
// handlers to continue to read the request body while concurrently
// writing the response. However, such behavior may not be supported
// by all HTTP/2 clients. Handlers should read before writing if
// possible to maximize compatibility.
Write([][byte](https://golang.org/pkg/builtin/#byte)) ([int](https://golang.org/pkg/builtin/#int), [error](https://golang.org/pkg/builtin/#error))
// WriteHeader sends an HTTP response header with the provided
// status code.
//
// If WriteHeader is not called explicitly, the first call to Write
// will trigger an implicit WriteHeader(http.StatusOK).
// Thus explicit calls to WriteHeader are mainly used to
// send error codes.
//
// The provided code must be a valid HTTP 1xx-5xx status code.
// Only one header may be written. Go does not currently
// support sending user-defined 1xx informational headers,
// with the exception of 100-continue response header that the
// Server sends automatically when the Request.Body is read.
WriteHeader(statusCode [int](https://golang.org/pkg/builtin/#int))
}</pre>
其他的暂时就不讲了,太难了,老铁
完整总结的代码(其实和上面一样的):
package main
/* http 包的练习 */
import (
"fmt"
"net/http"
"io/ioutil"
"html"
_ "log"
)
func easy_test(url string){
resp, err := http.Get(url)
if err != nil{
fmt.Printf("%v", err)
return
}
defer resp.Body.Close() // 入站是当前内存区域的 执行, 和主函数分开的,每个块内存都可以有自己的 压栈
defer fmt.Printf("请求函数执行结束")
body, _ := ioutil.ReadAll(resp.Body)
fmt.Printf("%s", body)
return
}
func simple_server(){
http.HandleFunc("/my_name", name_haddler)
http.HandleFunc("/url", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h1>Hello, %q</h1>", html.EscapeString(r.URL.Path))
})
http.ListenAndServe(":8080", nil)
}
func name_haddler(w http.ResponseWriter, r *http.Request){
fmt.Fprintf(w, "<h1>hello yxl</h1>")
}
// 事例
// FileServer
// FileServer (DotFileHiding)
// FileServer (StripPrefix)
// Get
// Handle
// HandleFunc
// Hijacker
// ListenAndServe
// ListenAndServeTLS
// NotFoundHandler
// ResponseWriter (Trailers)
// ServeMux.Handle
// Server.Shutdown
// StripPrefix
// FileServer func FileServer(root FileSystem) Handler
func FileServer(){
http.ListenAndServe(":8081", http.FileServer(http.Dir("F:/go/")))
}
// FileServer (DotFileHiding)
func FileServer_DotFileHiding(){
// 这个看不懂啊
}
// FileServer (StripPrefix)
func FileServer_StripPrefix(){
// 这个就是子在 FileServer 基础上加了一个前缀路由地址
http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("F:/go/"))))
http.ListenAndServe(":8082", nil)
}
// Get func Get(url string) (resp *Response, err error)
func get(){
// 请求一个地址, 如果状态码是 30x x 是12378之一 就自动重定向,最多 10 次
// 参见 11 行 easy_test
}
// Handle func Handle(pattern string, handler Handler)
func handle(){
// 就是添加路由,匹配对应一个函数酱紫
// 这个就暂时补贴代码了
// 路由匹配处理函数(结构体类型), 要实现 Handler 接口的 ServeHTTP(w http.ResponseWriter, r *http.Request) 方法
}
// HandleFunc func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
func HandleFunc(){
// 和 Handle 几乎一样,唯一不同的是参数不一样,这个是自己定义一个
// xx(w http.ResponseWriter, r *http.Request) 这样的函数,儿不必叫 ServeHTTP 名字,因为 HandleFunc 函数第二个参数是 直接一个函数类型,二不是 有ServeHTTP 函数的 Handler 接口类型
// 参见 simple_server 24-37 行
}
// ListenAndServe func ListenAndServe(addr string, handler Handler) error
func ListenAndServe(){
// 参见
}
// ListenAndServeTLS func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error
func ListenAndServeTLS(){
// ListenAndServe HTTPS 版本
}
// NotFoundHandler func NotFoundHandler() Handler
func NotFoundHandler(){
// 404 对应的处理
mux.Handle("/resources", http.NotFoundHandler())
}
// ResponseWriter interface
func ResponseWriter(){
// 上面所有的 处理函数,都直接或者间接实现这个 函数了
// 如: func(w http.ResponseWriter, r *http.Request)
// 还有 Handler 接口定义的 ServeHTTP(ResponseWriter, *Request) 函数(同包就省略了 http.)
}
// func (*ServeMux) ServeMux func (mux *ServeMux) Handle(pattern string, handler Handler)
func ServeMux_ServeMux(){
// 这个不太懂
}
// func (*Server) Shutdown func (srv *Server) Shutdown(ctx context.Context) error
func Server_Shutdown(){
// 这个也不会
}
// StripPrefix func StripPrefix(prefix string, h Handler) Handler
func StripPrefix(){
// 删除请求的特定前缀
// 参见: FileServer_StripPrefix 70 行
}
func main(){
// easy_test("https://sunrain.xyz")
// simple_server()
FileServer()
}
有疑问加站长微信联系(非本文作者)