golang之网络开发
1. TCP/UDP Server/Client开发
net包提供network I/O开发接口,包括TCP/IP、UDP、DNS和Unix domain sockets。
常用开发一般仅需要最基础接口或函数:
服务器:net.Listen(),net.Accept()
ln, err := net.Listen("tcp", ":8080")
if err != nil {
// handle error
}
for {
conn, err := ln.Accept()
if err != nil {
// handle error
}
go handleConnection(conn)
}
客户端:net.Dial()
conn, err := net.Dial("tcp", "golang.org:80")
if err != nil {
// handle error
}
fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
status, err := bufio.NewReader(conn).ReadString('\n')
// ...
相关API定义:
func Listen(network, address string) (Listener, error)
func (l *TCPListener) Accept() (Conn, error)
func Dial(network, address string) (Conn, error)
2. web开发
net/http包为web开发提供支持,能很简单地对Web的路由,静态文件,模版,cookie等数据进行设置和操作。
主要是两步:设置访问路由,设置监听端口(转发路由:根据用户请求调用不同路由函数)。
type HandlerFunc func(w http.ResponseWriter, r *http.Request)
func (f HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) // ServeHTTP calls f(w, r).
func HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request))
type Handler interface {
ServeHTTP(http.ResponseWriter, *http.Request)
}
func Handle(pattern string, handler http.Handler)
func ListenAndServe(addr string, handler http.Handler) error
ListenAndServe starts an HTTP server with a given address and handler. The handler is usually nil, which means to use DefaultServeMux. 若此时给定Handler,则采用给定的Handler(给定的handler需实现ServeHTTP()函数的接口)。
Handle and HandleFunc add handlers to DefaultServeMux.
DefaultServeMux路由规则:
- URL分为两种,末尾为/:表示一个子树,后面可以跟其他子路经;末尾不是/,表示一个叶子,固定路径。以/结尾的URL可以匹配它的任何子路经,比如/images会匹配/images/cute-cat.
- 它采用最长匹配原则,如果有多个匹配,一定采用匹配路径最长的那个进行处理。
- 如果没有任何匹配项,返回404错误。
Handle()的参数为地址匹配字符串和handler接口,handler需要实现ServeHTTP()函数的接口。
HandleFunc()的参数是地址匹配字符串和函数handle,函数handle等同http.Handler接口要实现的函数。
http.Handle("/foo", fooHandler) http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
http.Handle("/zoo", http.HandlerFunc(zoo)) // 直接将函数zoo赋值为http.HandlerFunc
log.Fatal(http.ListenAndServe(":8080", nil))
package main import (
"fmt"
"net/http"
_"html"
"log"
) type fooHandler struct{
} func (f fooHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){
fmt.Fprintf(w, "Hello, first!\n")
} func main(){
http.Handle("/foo", fooHandler{}) http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request){
fmt.Fprintf(w, "Hello, %q\n", r.URL.Path)
}) log.Fatal(http.ListenAndServe(":8088", nil))
} # go build -o first first.go
# ./first &
$ curl localhost:/foo
Hello, first!
$ curl localhost:/bar?house=wang
Hello, "/bar"
Handler示例
简单应用
Get, Head, Post and PostForm make HTTP or HTTPS requests:
resp, err := http.Get("http://example.com/")
...
resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf)
...
resp, err := http.PostForm("http://example.com/form", url.Values{"key": {"Value"}, "id": {""}})
...
defer resp.Body.Close() // when finished
body, err := ioutil.ReadAll(resp.Body)
复杂应用
client := &http.Client{
CheckRedirect: redirectPolicyFunc,
} resp, err := client.Get("http://example.com")
// ... req, err := http.NewRequest("GET", "http://example.com", nil)
// ...
req.Header.Add("If-None-Match", `W/"wyzzy"`)
resp, err := client.Do(req)
// ...
1)通过创建Client控制HTTP客户端client headers, redirect policy and other settings
tr := &http.Transport{
MaxIdleConns: ,
IdleConnTimeout: * time.Second,
DisableCompression: true,
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://example.com")
2)通过创建Transport控制客户端三层四层配置,如TLS,keepalives,compression等
注:Client和Transport可并发运行。
s := &http.Server{
Addr: ":8080",
Handler: myHandler,
ReadTimeout: * time.Second,
WriteTimeout: * time.Second,
MaxHeaderBytes: << ,
}
log.Fatal(s.ListenAndServe())
3)通过创建Server控制服务器端配置
常用量和函数
const (
MethodGet = "GET"
MethodHead = "HEAD"
MethodPost = "POST"
MethodPut = "PUT"
MethodPatch = "PATCH" // RFC 5789
MethodDelete = "DELETE"
MethodConnect = "CONNECT"
MethodOptions = "OPTIONS"
MethodTrace = "TRACE"
)const DefaultMaxHeaderBytes = << // 1 MB
const DefaultMaxIdleConnsPerHost =
var DefaultServeMux = &defaultServeMux
var ErrHandlerTimeout = errors.New("http: Handler timeout")
const (
StatusContinue = // RFC 7231, 6.2.1
StatusSwitchingProtocols = // RFC 7231, 6.2.2
StatusProcessing = // RFC 2518, 10.1
StatusEarlyHints = // RFC 8297 StatusOK = // RFC 7231, 6.3.1
StatusCreated = // RFC 7231, 6.3.2
StatusAccepted = // RFC 7231, 6.3.3
StatusNonAuthoritativeInfo = // RFC 7231, 6.3.4
StatusNoContent = // RFC 7231, 6.3.5
StatusResetContent = // RFC 7231, 6.3.6
StatusPartialContent = // RFC 7233, 4.1
StatusMultiStatus = // RFC 4918, 11.1
StatusAlreadyReported = // RFC 5842, 7.1
StatusIMUsed = // RFC 3229, 10.4.1 StatusMultipleChoices = // RFC 7231, 6.4.1
StatusMovedPermanently = // RFC 7231, 6.4.2
StatusFound = // RFC 7231, 6.4.3
StatusSeeOther = // RFC 7231, 6.4.4
StatusNotModified = // RFC 7232, 4.1
StatusUseProxy = // RFC 7231, 6.4.5 StatusTemporaryRedirect = // RFC 7231, 6.4.7
StatusPermanentRedirect = // RFC 7538, 3 StatusBadRequest = // RFC 7231, 6.5.1
StatusUnauthorized = // RFC 7235, 3.1
StatusPaymentRequired = // RFC 7231, 6.5.2
StatusForbidden = // RFC 7231, 6.5.3
StatusNotFound = // RFC 7231, 6.5.4
StatusMethodNotAllowed = // RFC 7231, 6.5.5
StatusNotAcceptable = // RFC 7231, 6.5.6
StatusProxyAuthRequired = // RFC 7235, 3.2
StatusRequestTimeout = // RFC 7231, 6.5.7
StatusConflict = // RFC 7231, 6.5.8
StatusGone = // RFC 7231, 6.5.9
StatusLengthRequired = // RFC 7231, 6.5.10
StatusPreconditionFailed = // RFC 7232, 4.2
StatusRequestEntityTooLarge = // RFC 7231, 6.5.11
StatusRequestURITooLong = // RFC 7231, 6.5.12
StatusUnsupportedMediaType = // RFC 7231, 6.5.13
StatusRequestedRangeNotSatisfiable = // RFC 7233, 4.4
StatusExpectationFailed = // RFC 7231, 6.5.14
StatusTeapot = // RFC 7168, 2.3.3
StatusMisdirectedRequest = // RFC 7540, 9.1.2
StatusUnprocessableEntity = // RFC 4918, 11.2
StatusLocked = // RFC 4918, 11.3
StatusFailedDependency = // RFC 4918, 11.4
StatusTooEarly = // RFC 8470, 5.2.
StatusUpgradeRequired = // RFC 7231, 6.5.15
StatusPreconditionRequired = // RFC 6585, 3
StatusTooManyRequests = // RFC 6585, 4
StatusRequestHeaderFieldsTooLarge = // RFC 6585, 5
StatusUnavailableForLegalReasons = // RFC 7725, 3 StatusInternalServerError = // RFC 7231, 6.6.1
StatusNotImplemented = // RFC 7231, 6.6.2
StatusBadGateway = // RFC 7231, 6.6.3
StatusServiceUnavailable = // RFC 7231, 6.6.4
StatusGatewayTimeout = // RFC 7231, 6.6.5
StatusHTTPVersionNotSupported = // RFC 7231, 6.6.6
StatusVariantAlsoNegotiates = // RFC 2295, 8.1
StatusInsufficientStorage = // RFC 4918, 11.5
StatusLoopDetected = // RFC 5842, 7.2
StatusNotExtended = // RFC 2774, 7
StatusNetworkAuthenticationRequired = // RFC 6585, 6
)
StatusOK = 200 // RFC 7231, 6.3.1
func Error(w ResponseWriter, error string, code int)
Error replies to the request with the specified error message and HTTP code.
It does not otherwise end the request; the caller should ensure no further writes are done to w.
The error message should be plain text. func DetectContentType(data []byte) string
DetectContentType always returns a valid MIME type:
if it cannot determine a more specific one, it returns "application/octet-stream". func Handle(pattern string, handler Handler)
Handle registers the handler for the given pattern in the DefaultServeMux.
The documentation for ServeMux explains how patterns are matched. func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
HandleFunc registers the handler function for the given pattern in the DefaultServeMux.
The documentation for ServeMux explains how patterns are matched. func ListenAndServe(addr string, handler Handler) error
The handler is typically nil, in which case the DefaultServeMux is used.
ListenAndServe always returns a non-nil error. func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error func NotFound(w ResponseWriter, r *Request)
NotFound replies to the request with an HTTP not found error.
ParseHTTPVersion parses a HTTP version string. "HTTP/1.0" returns (, , true). func Redirect(w ResponseWriter, r *Request, url string, code int)
The provided code should be in the 3xx range and is usually StatusMovedPermanently, StatusFound or StatusSeeOther.
If the Content-Type header has not been set, Redirect sets it to "text/html; charset=utf-8" and writes a small HTML body.
Setting the Content-Type header to any value, including nil, disables that behavior. func Serve(l net.Listener, handler Handler) error
Serve accepts incoming HTTP connections on the listener l, creating a new service goroutine for each.
The service goroutines read requests and then call handler to reply to them.
The handler is typically nil, in which case the DefaultServeMux is used.
Serve always returns a non-nil error. func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time, content io.ReadSeeker)
ServeContent replies to the request using the content in the provided ReadSeeker.
The main benefit of ServeContent over io.Copy is that it handles Range requests properly, sets the MIME type, and handles If-Match,
If-Unmodified-Since, If-None-Match, If-Modified-Since, and If-Range requests. func ServeFile(w ResponseWriter, r *Request, name string)
ServeFile replies to the request with the contents of the named file or directory. func StatusText(code int) string
StatusText returns a text for the HTTP status code. It returns the empty string if the code is unknown.
func Error(w ResponseWriter, error string, code int)
Error replies to the request with the specified error message and HTTP code.
It does not otherwise end the request; the caller should ensure no further writes are done to w.
The error message should be plain text. func DetectContentType(data []byte) string
DetectContentType always returns a valid MIME type:
if it cannot determine a more specific one, it returns "application/octet-stream".
type Response struct {
Status string // e.g. "200 OK"
StatusCode int // e.g. 200
Proto string // e.g. "HTTP/1.0"
ProtoMajor int // e.g. 1
ProtoMinor int // e.g. 0 // Header maps header keys to values. If the response had multiple
// headers with the same key, they may be concatenated, with comma
// delimiters. (RFC 7230, section 3.2.2 requires that multiple headers
// be semantically equivalent to a comma-delimited sequence.) When
// Header values are duplicated by other fields in this struct (e.g.,
// ContentLength, TransferEncoding, Trailer), the field values are
// authoritative.
//
// Keys in the map are canonicalized (see CanonicalHeaderKey).
Header Header // Body represents the response body.
//
// The response body is streamed on demand as the Body field
// is read. If the network connection fails or the server
// terminates the response, Body.Read calls return an error.
//
// The http Client and Transport guarantee that Body is always
// non-nil, even on responses without a body or responses with
// a zero-length body. It is the caller's responsibility to
// close Body. The default HTTP client's Transport may not
// reuse HTTP/1.x "keep-alive" TCP connections if the Body is
// not read to completion and closed.
//
// The Body is automatically dechunked if the server replied
// with a "chunked" Transfer-Encoding.
//
// As of Go 1.12, the Body will also implement io.Writer
// on a successful "101 Switching Protocols" response,
// as used by WebSockets and HTTP/2's "h2c" mode.
Body io.ReadCloser // ContentLength records the length of the associated content. The
// value -1 indicates that the length is unknown. Unless Request.Method
// is "HEAD", values >= 0 indicate that the given number of bytes may
// be read from Body.
ContentLength int64 // Contains transfer encodings from outer-most to inner-most. Value is
// nil, means that "identity" encoding is used.
TransferEncoding []string // Close records whether the header directed that the connection be
// closed after reading Body. The value is advice for clients: neither
// ReadResponse nor Response.Write ever closes a connection.
Close bool // Uncompressed reports whether the response was sent compressed but
// was decompressed by the http package. When true, reading from
// Body yields the uncompressed content instead of the compressed
// content actually set from the server, ContentLength is set to -1,
// and the "Content-Length" and "Content-Encoding" fields are deleted
// from the responseHeader. To get the original response from
// the server, set Transport.DisableCompression to true.
Uncompressed bool // Go 1.7 // Trailer maps trailer keys to values in the same
// format as Header.
//
// The Trailer initially contains only nil values, one for
// each key specified in the server's "Trailer" header
// value. Those values are not added to Header.
//
// Trailer must not be accessed concurrently with Read calls
// on the Body.
//
// After Body.Read has returned io.EOF, Trailer will contain
// any trailer values sent by the server.
Trailer Header // Request is the request that was sent to obtain this Response.
// Request's Body is nil (having already been consumed).
// This is only populated for Client requests.
Request *Request // TLS contains information about the TLS connection on which the
// response was received. It is nil for unencrypted responses.
// The pointer is shared between responses and should not be
// modified.
TLS *tls.ConnectionState // Go 1.3
}
http.Response
type Request struct {
// Method specifies the HTTP method (GET, POST, PUT, etc.).
// For client requests, an empty string means GET.
//
// Go's HTTP client does not support sending a request with
// the CONNECT method. See the documentation on Transport for
// details.
Method string // URL specifies either the URI being requested (for server
// requests) or the URL to access (for client requests).
//
// For server requests, the URL is parsed from the URI
// supplied on the Request-Line as stored in RequestURI. For
// most requests, fields other than Path and RawQuery will be
// empty. (See RFC 7230, Section 5.3)
//
// For client requests, the URL's Host specifies the server to
// connect to, while the Request's Host field optionally
// specifies the Host header value to send in the HTTP
// request.
URL *url.URL // The protocol version for incoming server requests.
//
// For client requests, these fields are ignored. The HTTP
// client code always uses either HTTP/1.1 or HTTP/2.
// See the docs on Transport for details.
Proto string // "HTTP/1.0"
ProtoMajor int //
ProtoMinor int // 0 // Header contains the request header fields either received
// by the server or to be sent by the client.
//
// If a server received a request with header lines,
//
// Host: example.com
// accept-encoding: gzip, deflate
// Accept-Language: en-us
// fOO: Bar
// foo: two
//
// then
//
// Header = map[string][]string{
// "Accept-Encoding": {"gzip, deflate"},
// "Accept-Language": {"en-us"},
// "Foo": {"Bar", "two"},
// }
//
// For incoming requests, the Host header is promoted to the
// Request.Host field and removed from the Header map.
//
// HTTP defines that header names are case-insensitive. The
// request parser implements this by using CanonicalHeaderKey,
// making the first character and any characters following a
// hyphen uppercase and the rest lowercase.
//
// For client requests, certain headers such as Content-Length
// and Connection are automatically written when needed and
// values in Header may be ignored. See the documentation
// for the Request.Write method.
Header Header // Body is the request's body.
//
// For client requests, a nil body means the request has no
// body, such as a GET request. The HTTP Client's Transport
// is responsible for calling the Close method.
//
// For server requests, the Request Body is always non-nil
// but will return EOF immediately when no body is present.
// The Server will close the request body. The ServeHTTP
// Handler does not need to.
Body io.ReadCloser // GetBody defines an optional func to return a new copy of
// Body. It is used for client requests when a redirect requires
// reading the body more than once. Use of GetBody still
// requires setting Body.
//
// For server requests, it is unused.
GetBody func() (io.ReadCloser, error) // Go 1.8 // ContentLength records the length of the associated content.
// The value -1 indicates that the length is unknown.
// Values >= 0 indicate that the given number of bytes may
// be read from Body.
//
// For client requests, a value of 0 with a non-nil Body is
// also treated as unknown.
ContentLength int64 // TransferEncoding lists the transfer encodings from outermost to
// innermost. An empty list denotes the "identity" encoding.
// TransferEncoding can usually be ignored; chunked encoding is
// automatically added and removed as necessary when sending and
// receiving requests.
TransferEncoding []string // Close indicates whether to close the connection after
// replying to this request (for servers) or after sending this
// request and reading its response (for clients).
//
// For server requests, the HTTP server handles this automatically
// and this field is not needed by Handlers.
//
// For client requests, setting this field prevents re-use of
// TCP connections between requests to the same hosts, as if
// Transport.DisableKeepAlives were set.
Close bool // For server requests, Host specifies the host on which the
// URL is sought. For HTTP/1 (per RFC 7230, section 5.4), this
// is either the value of the "Host" header or the host name
// given in the URL itself. For HTTP/2, it is the value of the
// ":authority" pseudo-header field.
// It may be of the form "host:port". For international domain
// names, Host may be in Punycode or Unicode form. Use
// golang.org/x/net/idna to convert it to either format if
// needed.
// To prevent DNS rebinding attacks, server Handlers should
// validate that the Host header has a value for which the
// Handler considers itself authoritative. The included
// ServeMux supports patterns registered to particular host
// names and thus protects its registered Handlers.
//
// For client requests, Host optionally overrides the Host
// header to send. If empty, the Request.Write method uses
// the value of URL.Host. Host may contain an international
// domain name.
Host string // Form contains the parsed form data, including both the URL
// field's query parameters and the PATCH, POST, or PUT form data.
// This field is only available after ParseForm is called.
// The HTTP client ignores Form and uses Body instead.
Form url.Values // PostForm contains the parsed form data from PATCH, POST
// or PUT body parameters.
//
// This field is only available after ParseForm is called.
// The HTTP client ignores PostForm and uses Body instead.
PostForm url.Values // Go 1.1 // MultipartForm is the parsed multipart form, including file uploads.
// This field is only available after ParseMultipartForm is called.
// The HTTP client ignores MultipartForm and uses Body instead.
MultipartForm *multipart.Form // Trailer specifies additional headers that are sent after the request
// body.
//
// For server requests, the Trailer map initially contains only the
// trailer keys, with nil values. (The client declares which trailers it
// will later send.) While the handler is reading from Body, it must
// not reference Trailer. After reading from Body returns EOF, Trailer
// can be read again and will contain non-nil values, if they were sent
// by the client.
//
// For client requests, Trailer must be initialized to a map containing
// the trailer keys to later send. The values may be nil or their final
// values. The ContentLength must be 0 or -1, to send a chunked request.
// After the HTTP request is sent the map values can be updated while
// the request body is read. Once the body returns EOF, the caller must
// not mutate Trailer.
//
// Few HTTP clients, servers, or proxies support HTTP trailers.
Trailer Header // RemoteAddr allows HTTP servers and other software to record
// the network address that sent the request, usually for
// logging. This field is not filled in by ReadRequest and
// has no defined format. The HTTP server in this package
// sets RemoteAddr to an "IP:port" address before invoking a
// handler.
// This field is ignored by the HTTP client.
RemoteAddr string // RequestURI is the unmodified request-target of the
// Request-Line (RFC 7230, Section 3.1.1) as sent by the client
// to a server. Usually the URL field should be used instead.
// It is an error to set this field in an HTTP client request.
RequestURI string // TLS allows HTTP servers and other software to record
// information about the TLS connection on which the request
// was received. This field is not filled in by ReadRequest.
// The HTTP server in this package sets the field for
// TLS-enabled connections before invoking a handler;
// otherwise it leaves the field nil.
// This field is ignored by the HTTP client.
TLS *tls.ConnectionState // Cancel is an optional channel whose closure indicates that the client
// request should be regarded as canceled. Not all implementations of
// RoundTripper may support Cancel.
//
// For server requests, this field is not applicable.
//
// Deprecated: Set the Request's context with NewRequestWithContext
// instead. If a Request's Cancel field and context are both
// set, it is undefined whether Cancel is respected.
Cancel <-chan struct{} // Go 1.5 // Response is the redirect response which caused this request
// to be created. This field is only populated during client
// redirects.
Response *Response // Go 1.7
// contains filtered or unexported fields
}
http.Request
HTTP/2
HTTP/2协议握手分2种方式,一种叫h2,一种叫h2c。
h2要求必须使用TLS加密,在TLS握手期间会顺带完成HTTPS/2协议的协商,如果协商失败(比如客户端不支持或者服务端不支持),则会使用HTTPS/1继续后续通讯。
h2c不使用TLS,而是多了一次基于HTTP协议的握手往返来完成向HTTP/2协议的升级,一般不建议使用。
Golang的http库在设计API时并没有支持用户使用h2c,而是鼓励使用h2。
GO的http库默认支持HTTP/2协议,只要我们使用TLS则会默认启动HTTP/2特性,如果协商失败则蜕化为HTTPS/1。。
对http Client或者Server做一些更加定制化的配置时,就会覆盖掉http库的默认行为,从而导致无法启用HTTP/2协议。
只要server端开启TLS服务即可启用HTTP/2。
package main import (
"fmt"
"net/http"
"os"
"strconv"
) var Addr string = ":8088" func handler(w http.ResponseWriter, r *http.Request){
r.ParseForm()
// fmt.Println(r.Form)
// fmt.Println(r.Form["numa"])
// fmt.Println(r.Form["numb"])
numa, _:= strconv.Atoi(r.Form["numa"][])
numb, _:= strconv.Atoi(r.Form["numb"][])
fmt.Fprintf(w, "%d\n", numa+numb)
} func main(){
http.HandleFunc("/", handler)
_, err := os.Open("cert/server.crt")
if err != nil {
fmt.Println("Can't open server.crt")
panic(err)
} fmt.Printf("listen...[%s]\n", Addr)
err = http.ListenAndServeTLS(Addr, "cert/server.crt",
"cert/server.key", nil)
if err != nil {
fmt.Println(err)
}
}
sever.go
package main import (
"log"
"net/http"
) func main(){
srv := &http.Server{Addr: ":8088", Handler: http.HandlerFunc(handle)} log.Printf("Serving on https://server:8088")
log.Fatal(srv.ListenAndServeTLS("cert/server.crt", "cert/server.key"))
} func handle(w http.ResponseWriter, r *http.Request){
w.Write([]byte("Hello"))
}
除了使用ServeTLS/ListenAndServeTLS来启动支持HTTPS/2特性的服务端之外,还可以通过http2.ConfigureServer来为http.Server启动HTTPS/2特性并直接使用Serve来启动服务。
package main import (
"fmt"
"crypto/tls"
"crypto/x509"
"flag"
"io/ioutil"
"log"
"net/http"
"golang.org/x/net/http2"
) var addr = flag.String("addr", "https://server:8088?numa=4&numb=6", "connect to")
var httpVer = flag.Int("httpVer", , "HTTP version") func main(){
flag.Parse() client := &http.Client{} caCert, err := ioutil.ReadFile("cert/ca.crt")
if err != nil {
log.Fatalf("Reading server certificate: %s", err)
} pool := x509.NewCertPool()
pool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
RootCAs: pool,
} switch *httpVer {
case :
client.Transport = &http.Transport {
TLSClientConfig: tlsConfig,
}
case :
client.Transport = &http2.Transport {
TLSClientConfig: tlsConfig,
}
} resp, err := client.Get(*addr)
if err != nil {
log.Fatalf("Failed get: %s", err)
}
defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalf("Failed reading response body: %s", err)
} fmt.Printf("Response %d: %s\nbody: %s\n", resp.StatusCode, resp.Proto, string(body))
}
client定制后要开启HTTP/2,需要配置Transport(或使用http2.ConfigureTransport(transport)
)。
$ ./cli -httpVer=
Response : HTTP/1.1
body: $ ./cli -httpVer=
Response : HTTP/2.0
body:
cookie相关
A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an HTTP response or the Cookie header of an HTTP request.
See https://tools.ietf.org/html/rfc6265 for details.
type Cookie struct {
Name string
Value string Path string // optional
Domain string // optional
Expires time.Time // optional
RawExpires string // for reading cookies only // MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
// MaxAge>0 means Max-Age attribute present and given in seconds
MaxAge int
Secure bool
HttpOnly bool
SameSite SameSite // Go 1.11
Raw string
Unparsed []string // Raw text of unparsed attribute-value pairs
} func (c *Cookie) String() string
String returns the serialization of the cookie for use in a Cookie header (if only Name and Value are set) or
a Set-Cookie response header (if other fields are set). If c is nil or c.Name is invalid, the empty string is returned. func SetCookie(w ResponseWriter, cookie *Cookie)
SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
The provided cookie must have a valid Name. Invalid cookies may be silently dropped.
r.URL参考net/url包,定义如下:
type URL struct {
Scheme string
Opaque string // encoded opaque data
User *Userinfo // username and password information
Host string // host or host:port
Path string // path (relative paths may omit leading slash)
RawPath string // encoded path hint (see EscapedPath method); added in Go 1.5
ForceQuery bool // append a query ('?') even if RawQuery is empty; added in Go 1.7
RawQuery string // encoded query values, without '?'
Fragment string // fragment for references, without '#'
}
resp, err := http.PostForm("http://example.com/form", url.Values{"key": {"Value"}, "id": {"123"}})
示例应用如下:
表单form可由两种方式提交GET或POST,GET方式form表单键值对直接跟在url后(?分割,&链接),POST方式Form以请求body方式发送。
import (
"fmt"
"net/http"
"strings"
"log"
) func main(){
http.HandleFunc("/", sayhelloName) // 设置访问路由
err := http.ListenAndServe(":9090", nil) // 设置监听端口
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
} func sayhelloName(w http.ResponseWriter, r *http.Request){
r.ParseForm()
fmt.Println("---------------")
fmt.Println(r.Form)
fmt.Println("path:", r.URL.Path)
fmt.Println("scheme:", r.URL.Scheme)
fmt.Println(r.Form["url_long"])
fmt.Println("====")
for k, v := range r.Form{
fmt.Println("key:", k)
fmt.Println("val:", strings.Join(v, " "))
}
fmt.Fprintf(w, "Hello wang!")
}
godoc提供了一个web开发示例Writing Web Applications,用到了net/http,html/template, regexp,闭包等技术:
package main import (
_"fmt"
"io/ioutil"
"net/http"
"log"
"html/template"
"regexp"
_"errors"
) type Page struct {
Title string
Body []byte
} func (p *Page) save() error {
filename := p.Title + ".txt"
return ioutil.WriteFile(filename, p.Body, )
} func loadPage(title string) (*Page, error){
filename := title + ".txt"
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &Page{Title: title, Body : body}, nil
} var templates *template.Template
var validPath *regexp.Regexp
func main(){
/*
p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")}
p1.save()
p2, _ := loadPage("TestPage")
fmt.Println(string(p2.Body))
*/
// import templates
// panic when failed
templates = template.Must(template.ParseFiles("edit.html", "view.html")) // validation
validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
/*
http.HandleFunc("/view/", viewHandler)
http.HandleFunc("/edit/", editHandler)
http.HandleFunc("/save/", saveHandler)
*/
http.HandleFunc("/view/", makeHandler(viewHandler))
http.HandleFunc("/edit/", makeHandler(editHandler))
http.HandleFunc("/save/", makeHandler(saveHandler))
log.Fatal(http.ListenAndServe(":8090", nil))
}
/*
func getTitle(w http.ResponseWriter, r *http.Request)(string, error){
m := validPath.FindStringSubmatch(r.URL.Path)
if m == nil {
http.NotFound(w, r)
return "", errors.New("Invalid Page Title")
}
return m[2], nil // The title is the second subexpression
}
*/
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request){
m := validPath.FindStringSubmatch(r.URL.Path)
if m == nil {
http.NotFound(w, r)
return
}
fn(w, r, m[])
}
} /*
func viewHandler(w http.ResponseWriter, r *http.Request){
title := r.URL.Path[len("/view/"):]
p, _ := loadPage(title)
fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
}
*/ //func viewHandler(w http.ResponseWriter, r *http.Request){
func viewHandler(w http.ResponseWriter, r *http.Request, title string){
// title := r.URL.Path[len("/view/"):]
/*
title, err := getTitle(w, r)
if err != nil {
return
}
*/
p, err:= loadPage(title)
if err != nil {
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
return
}
//t, _:= template.ParseFiles("view.html")
//t.Execute(w, p)
renderTemplate(w, "view", p)
} /*
func editHandler(w http.ResponseWriter, r *http.Request){
title := r.URL.Path[len("/edit/"):]
p, err := loadPage(title)
if err != nil {
p = &Page{Title: title}
}
fmt.Fprintf(w, "<h1>Editing %s</h1>" +
"<form action=\"/save/%s\" method=\"POST\">" +
"<textarea name=\"body\">%s</textarea><br>" +
"<input type=\"submit\" value=\"Save\">" +
"</form>",
p.Title, p.Title, p.Body)
}
*/
//func editHandler(w http.ResponseWriter, r*http.Request){
func editHandler(w http.ResponseWriter, r*http.Request, title string){
// title := r.URL.Path[len("/edit/"):]
/*
title, err := getTitle(w, r)
if err != nil {
return
}
*/
p, err := loadPage(title)
if err != nil {
p = &Page{Title: title}
}
// t, _:= template.ParseFiles(edit.html)
// t.Execute(w, p)
renderTemplate(w, "edit", p)
} //func saveHandler(w http.ResponseWriter, r *http.Request){
func saveHandler(w http.ResponseWriter, r *http.Request, title string){
// title := r.URL.Path[len("/save/"):]
/*
title , err := getTitle(w, r)
if err != nil {
return
}
*/
body := r.FormValue("body")
p := &Page{Title: title, Body: []byte(body)}
err := p.save()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/view/"+title, http.StatusFound)
} func renderTemplate(w http.ResponseWriter, tmpl string, p *Page){
/*
t, err := template.ParseFiles(tmpl + ".html")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
} err = t.Execute(w, p)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
*/
err := templates.ExecuteTemplate(w, tmpl+".html", p)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
参考:
https://www.kancloud.cn/kancloud/the-way-to-go/165098 go入门指南
http://wiki.jikexueyuan.com/project/go-web-programming/03.3.html go web编程
- Go语言练习:网络编程实例——简易图片上传网站 photoweb
Golang爬虫全攻略 网络应用解析
golang之网络开发的更多相关文章
- GoLang之网络
GoLang之网络 Go语言标准库里提供的net包,支持基于IP层.TCP/UDP层及更高层面(如HTTP.FTP.SMTP)的网络操作,其中用于IP层的称为Raw Socket. net包的Dial ...
- Golang+Protobuf+PixieJS 开发 Web 多人在线射击游戏(原创翻译)
简介 Superstellar 是一款开源的多人 Web 太空游戏,非常适合入门 Golang 游戏服务器开发. 规则很简单:摧毁移动的物体,不要被其他玩家和小行星杀死.你拥有两种资源 - 生命值(h ...
- iOS开发系列--网络开发
概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力 ...
- 新华龙电子推出最新网络开发板(W5100&W5500方案)
2014/12/16 | Filed under: TCP/IP芯片 and tagged with: C8051, W5100, W5500, 新华龙电子, 网络开发板 42 Views 深圳新华龙 ...
- IOS网络开发概述
概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力 ...
- 网络开发库从libuv说到epoll
引言 这篇博文可能有点水,主要将自己libuv的学习过程和理解. 简单谈方法. 有点杂. 那我们开始吧. 首先介绍 githup . 这个工具特别好用. 代码托管. 如果不FQ可能有点卡. 但是应该试 ...
- IOS开发之网络开发工具
IOS开发之网络开发工具 做移动端开发 常常会涉及到几个模块:1.网络检測 2.网络请求get和post请求 3.文件上传 4.文件下载 5.断点续传 如今将这些一一分享给大家 ,也欢迎 ...
- j2me必备之网络开发数据处理
第9章 无线网络开发MIDP提供了一组通用的网络开发接口,用来针对不同的无线网络应用可以采取不同的开发接口.基于CLDC的网络支持是由统一网络连接框架(Generic Connection Frame ...
- 基于uIP和uC/OS-II嵌入式网络开发
基于uIP和uC/OS-II嵌入式网络开发 ——uIP主动发送数据分析 摘要:uIP协议栈简单易用,可以为16位单片机或者是更低级的处理器使用,占用的资源很少,相关移植网上有详细介绍,本文主要讨论uI ...
随机推荐
- 锐捷交换机如何配置远程管理地址(telnet)
基本命令如下: hostname(config)#username admin password 123456 ------>telnet 登录账号为admin密码为123456 hostna ...
- MongoDB开发深入之一:文档数据关系模型详解(一对多,多对多)
文档关联模型通常有3种方式: 嵌入式(一对一.一对多) 后期手动统一ID处理(一对多.多对多) References引用(一对一.一对多) 文档树模型通常有3种方式: 父引用(Parent Refer ...
- matlab学习笔记12_4rmfield,arrayfun,structfun,struct2cell,cell2struct
一起来学matlab-matlab学习笔记12 12_4 结构体 rmfield,arrayfun,structfun,struct2cell,cell2struct 觉得有用的话,欢迎一起讨论相互学 ...
- oracle 涨工资
declare cursor cemp is select empno ,sal from emp order by sal; --定义参数 pempno emp.empno%type; psal e ...
- [转]java 根据模板文件生成word文档
链接地址:https://blog.csdn.net/ai_0922/article/details/82773466
- 【NPDP笔记】第三章 新产品流程
3.1 产品开发,风险与汇报的过程,开发实践和流程提升成功率 管控新产品失败的风险,随着成本增加,风险降低 知识能改改进决策,降低风险,决策框架 识别问题与机会 收集信息 组织记录,组织员工 外部 ...
- javascript中var、let、const的区别
这几天修改别人的js,发现声明变量有的用var,有的用let,那它们有什么区别呢? javascript中声明变量的方式有:var.let.const 1.var (1)作用域: 整个函数范围内,或者 ...
- VisualVM使用
sualVM是JDK自带的一个用于Java程序性能分析的工具 在JDK安装目录的bin文件夹下名称为 jvisualvm.exe 在左侧选择应用 (1)概述 应用程序和运行时环境的基本信息 基本参数 ...
- PHP pdo单例模式连接数据库
PHP pdo单例模式连接数据库<pre><?php class Db{ private static $pdo; public static function getPdo () ...
- Shadowing of static functions in Java
class A { static void fun() { System.out.println("A.fun()"); } } class B extends A { stati ...