1.package http
import "net/http"
Package http提供HTTP客户端和服务器实现。
- Get,Head,Post和PostForm发出HTTP(或HTTPS)请求:
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main(){
url := "http://www.baidu.com"
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(body))
}
客户端再结束后必须关闭response body。
package main
import (
"fmt"
"net/http"
"io/ioutil"
"bytes"
)
func main() {
//responce, err := http.Get("http://www.baidu.com")
//if err != nil {
// fmt.Println("net http get method failure, ", err)
//}
body := "{\"title\":\"xxxx\"}"
//post 方法参数,第一个参数为请求url,第二个参数 是contentType, 第三个参数为请求体
responce, err := http.Post("xxxx", "application/json", bytes.NewBuffer([]byte(body)))
if err != nil {
fmt.Println("net http post method err,", err)
}
defer responce.Body.Close()
rlt, _ := ioutil.ReadAll(responce.Body)
fmt.Println(string(rlt))
}
postfrom
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
)
func main() {
resp, err := http.PostForm("https://accounts.douban.com/j/mobile/login/basic", url.Values{"name": {"zhangsan@xx.com"}, "password": {"12356"}})
fmt.Println(resp.Request.URL)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(body))
}
Client
NewRequest 使用给定的Method,URL和可选的BODY参数,返回一个新的Request,适用于使用Client.Do或者Transport.RoundTrip.如果method参数为空字符串,默认是GET方法。
package main
import (
"fmt"
"io/ioutil"
"net/http"
"time"
)
func main() {
client := &http.Client{
Timeout: 3 * time.Second,
}
/*resp, err := client.Get("http://www.baidu.com")
if err != nil {
fmt.Println(err)
}*/
req, err := http.NewRequest("GET", "http://www.baidu.com", nil)
req.Header.Add("X-Requested-With", "XMLHttpRequest")
if err != nil {
fmt.Println(err)
}
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(body))
}
2.Handler
A Handler responds to an HTTP request.
type Handler interface {
// A ResponseWriter interface is used by an HTTP handler to
// construct an HTTP response.
//
// A ResponseWriter may not be used after the Handler.ServeHTTP method
// has returned.
ServeHTTP(ResponseWriter, *Request)
}
3.HandlerFunc
可以使任意的函数作为handlers来使用
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
无论是通过HandlerFunc组装的普通函数,还是实现了Handler接口的结构体,都可以作为url匹配的处理handler方法来使用。
4.ServeMux
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
// 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
}
}
// 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))
}
ServeMux是一个HTTP请求多路复用器。 它将每个传入请求的URL与已注册模式的列表进行匹配,并调用与URL最匹配的模式的处理程序。
package main
import (
"fmt"
"net/http"
)
type apiHandler struct{}
func (apiHandler) ServeHTTP(http.ResponseWriter, *http.Request) {}
func main() {
mux := http.NewServeMux()
mux.Handle("/api/", apiHandler{})
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
// The "/" pattern matches everything, so we need to check
// that we're at the root here.
if req.URL.Path != "/" {
http.NotFound(w, req)
return
}
fmt.Fprintf(w, "Welcome to the home page!")
})
}
默认的DefaultServeMux
package main
import (
"fmt"
"net/http"
)
func main() {
http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, world...")
}))
http.ListenAndServe(":8080", nil)
}
package main
import (
"fmt"
"net/http"
)
type UserRespone struct{}
func (*UserRespone) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome...")
}
func main() {
mux := http.NewServeMux()
mux.Handle("/", &UserRespone{})
http.ListenAndServe(":8080", mux)
}
5.Server
/ A Server defines parameters for running an HTTP server.
// The zero value for Server is a valid configuration.
type Server struct {
Addr string // TCP address to listen on, ":http" if empty
Handler Handler // handler to invoke, http.DefaultServeMux if nil
// TLSConfig optionally provides a TLS configuration for use
// by ServeTLS and ListenAndServeTLS. Note that this value is
// cloned by ServeTLS and ListenAndServeTLS, so it's not
// possible to modify the configuration with methods like
// tls.Config.SetSessionTicketKeys. To use
// SetSessionTicketKeys, use Server.Serve with a TLS Listener
// instead.
TLSConfig *tls.Config
// ReadTimeout is the maximum duration for reading the entire
// request, including the body.
//
// Because ReadTimeout does not let Handlers make per-request
// decisions on each request body's acceptable deadline or
// upload rate, most users will prefer to use
// ReadHeaderTimeout. It is valid to use them both.
ReadTimeout time.Duration
// ReadHeaderTimeout is the amount of time allowed to read
// request headers. The connection's read deadline is reset
// after reading the headers and the Handler can decide what
// is considered too slow for the body.
ReadHeaderTimeout time.Duration
// WriteTimeout is the maximum duration before timing out
// writes of the response. It is reset whenever a new
// request's header is read. Like ReadTimeout, it does not
// let Handlers make decisions on a per-request basis.
WriteTimeout time.Duration
// IdleTimeout is the maximum amount of time to wait for the
// next request when keep-alives are enabled. If IdleTimeout
// is zero, the value of ReadTimeout is used. If both are
// zero, ReadHeaderTimeout is used.
IdleTimeout time.Duration
// MaxHeaderBytes controls the maximum number of bytes the
// server will read parsing the request header's keys and
// values, including the request line. It does not limit the
// size of the request body.
// If zero, DefaultMaxHeaderBytes is used.
MaxHeaderBytes int
// TLSNextProto optionally specifies a function to take over
// ownership of the provided TLS connection when an NPN/ALPN
// protocol upgrade has occurred. The map key is the protocol
// name negotiated. The Handler argument should be used to
// handle HTTP requests and will initialize the Request's TLS
// and RemoteAddr if not already set. The connection is
// automatically closed when the function returns.
// If TLSNextProto is not nil, HTTP/2 support is not enabled
// automatically.
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
// ConnState specifies an optional callback function that is
// called when a client connection changes state. See the
// ConnState type and associated constants for details.
ConnState func(net.Conn, ConnState)
// ErrorLog specifies an optional logger for errors accepting
// connections, unexpected behavior from handlers, and
// underlying FileSystem errors.
// If nil, logging is done via the log package's standard logger.
ErrorLog *log.Logger
disableKeepAlives int32 // accessed atomically.
inShutdown int32 // accessed atomically (non-zero means we're in Shutdown)
nextProtoOnce sync.Once // guards setupHTTP2_* init
nextProtoErr error // result of http2.ConfigureServer if used
mu sync.Mutex
listeners map[*net.Listener]struct{}
activeConn map[*conn]struct{}
doneChan chan struct{}
onShutdown []func()
}
// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// If srv.Addr is blank, ":http" is used.
//
// ListenAndServe always returns a non-nil error. After Shutdown or Close,
// the returned error is ErrServerClosed.
func (srv *Server) ListenAndServe() error {
if srv.shuttingDown() {
return ErrServerClosed
}
addr := srv.Addr
if addr == "" {
addr = ":http"
}
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}
// 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()
}
示例:
package main
import (
"fmt"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome...")
})
server := http.Server{
Addr: ":8080",
Handler: mux,
}
server.ListenAndServe()
}
6.negroni
Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler.
Negroni middleware is evaluated in the order that they are added to the stack using the Use and UseHandler methods.
Negroni 不是一个框架,它是为了方便使用 net/http 而设计的一个库而已。
安装:
go get github.com/urfave/negroni
package main
import (
"github.com/urfave/negroni"
"net/http"
"fmt"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Welcome to the home page!")
})
n := negroni.Classic()
n.UseHandler(mux)
n.Run(":3000")
}
Negroni 没有带路由功能,使用 Negroni 时,需要找一个适合你的路由。不过好在 Go 社区里已经有相当多可用的路由,Negroni 更喜欢和那些完全支持 net/http 库的路由搭配使用,比如搭配 Gorilla Mux 路由器,这样使用:
安装
go get -u github.com/gorilla/mux
r := mux.NewRouter()
r.HandleFunc("/", HomeHandler)
r.HandleFunc("/products/{key}", ProductHandler)
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
n := negroni.New(Middleware1, Middleware2)
// Or use a middleware with the Use() function
n.Use(Middleware3)
// router goes last
n.UseHandler(r)
一般来说使用 net/http 方法, 并且将 Negroni 当作处理器传入, 这样可定制化更佳, 例如:
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/urfave/negroni"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Welcome to the home page!")
})
n := negroni.Classic() // 导入一些预设的中间件
n.UseHandler(mux)
s := &http.Server{
Addr: ":8080",
Handler: n,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())
}
本中间件接收 panic 跟错误代码 500 的响应。如果其他中间件写了响应代码或 Body 内容的话, 中间件会无法顺利地传送 500 错误给客户端, 因为客户端 已经收到 HTTP 响应。另外, 可以 像 Sentry 或 Airbrake 挂载 PanicHandlerFunc 来报 500 错误给系统。
默认情况下,这个中间件会简要输出日志信息到 STDOUT 上。当然你也可以通过 SetFormatter() 函数自定义输出的日志。
当发生崩溃时,同样你也可以通过 HTMLPanicFormatter 来显示美化的 HTML 输出结果。
func reportToSentry(info *negroni.PanicInformation) {
// 在这写些程式回报错误给Sentry
fmt.Println(info)
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Welcome to the home page!")
})
mux.HandleFunc("/er", func(w http.ResponseWriter, req *http.Request) {
panic("oh no")
})
n := negroni.Classic()
recovery := negroni.NewRecovery()
recovery.PanicHandlerFunc = reportToSentry
recovery.Formatter = &negroni.HTMLPanicFormatter{}
n.Use(recovery)
n.UseHandler(mux)
n.Run(":3000")
}