This is a creation in Article, where the information may have evolved or changed.
Studied the HTTP2 usage of Golang.
There are several concepts to be popularized first.
- H2, HTTP/2 built on top of TLS, as alpn identifier, two bytes, 0x68, 0x32, or HTTPS
- H2C, HTTP/2, which is built directly on TCP, lacks security assurances that HTTP
Before the HTTP/2 RFC document appears, the above version fields need to be added to the draft version number, similar to the H2-11,H2C-17
First wrote the code of a server
Import ("FMT" "html" "Net/http" "GOLANG.ORG/X/NET/HTTP2") func main () {var server http. Server HTTP2. Verboselogs = True server. ADDR = ": 8080" http2. Configureserver (&server, &HTTP2. server{}) http. Handlefunc ("/", Func (w http.) Responsewriter, R *http. Request) {fmt. fprintf (W, "URL:%q\n", HTML. Escapestring (R.url. Path)) Showrequestinfohandler (W, R)}) server. Listenandserve ()///Do not enable HTTPS, only http1.x//log is supported by default. Fatal (server. Listenandservetls ("Localhost.cert", "Localhost.key"))}func Showrequestinfohandler (w http. Responsewriter, R *http. Request) {//FMT. fprintf (W, "======")//Return W.header (). Set ("Content-type", "Text/plain") fmt. fprintf (W, "Method:%s\n", R.method) fmt. fprintf (W, "Protocol:%s\n", R.proto) fmt. fprintf (W, "Host:%s\n", R.host) fmt. fprintf (W, "Remoteaddr:%s\n", r.remoteaddr) fmt. fprintf (W, "RequestUri:%q\n", R.requesturi) fmt. fprintf (W, "URL:% #v \ n", R.url) fmt. fprintf (W, "Body.contenTlength:%d ( -1 means unknown) \ n ", R.contentlength) fmt. fprintf (W, "Close:%v (relevant for HTTP/1 only) \ n", R.close) fmt. fprintf (W, "TLS:% #v \ n", R.tls) fmt. fprintf (W, "\nheaders:\n") R.header.write (W)}
Server is used because you do not want to use HTTPS. Listenandserve (), I didn't think there was a hole here, wait for the introduction
Since the server uses HTTP non-TLS then the client uses non-TLS, see the code
Package Mainimport ("Crypto/tls" "FMT" "Io/ioutil" "Log" "Net" "Net/http" "golang.org/x/n ET/HTTP2 ") Func main () {URL: =" http://localhost:8080/"Client (URL)}func client (URL string) {log. SetFlags (log. Llongfile) TR: = &HTTP2. transport{//Unfortunately the server has degenerated into a http1.x allowhttp:true,//A non-encrypted link//tlsclientconfig: &tls. config{//Insecureskipverify:true,//}, Dialtls:func (NETW, addr string, cfg *tls. Config) (NET. Conn, error) {return net. Dial (NETW, addr)},} httpClient: = http. CLIENT{TRANSPORT:TR} resp, err: = Httpclient.get (URL) if err! = Nil {log. Fatal (ERR)} Defer resp. Body.close () If Resp. StatusCode! = http. Statusok {fmt. Println ("Resp StatusCode:", resp. StatusCode) return} body, err: = Ioutil. ReadAll (resp. Body) If err! = Nil {log. Fatal (Err)} FMT. Println ("resp. Body:\n ", String (Body)}
Since the HTTP2 client did not expose H2C mode, a
AllowHTTP: true, //充许非加密的链接DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) { return net.Dial(netw, addr) },
The intention is to implement the client H2C
We're done. Run the server, execute the client, print the results
Get http://localhost:8080/: Unexpected EOF
Look at the foggy, and then grab a bag to see
Paste picture. png
The server sent a http1.1 package to the client, and also close the clients link.
Server. Listenandserve ()//Do not enable HTTPS, only http1.x is supported by default
1.png
Since the server only supports HTTP1, then the client sends a HTTP2 request, of course, the server must close the link.
Then there is no way to solve, that is, the server and the client use H2C, the client is better to do allowhttp:true the non-encrypted link and
DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) { return net.Dial(netw, addr) },
The
server considers using a lower-level library HTTP2 library implementation, mostly using Servcon to directly replace Serv functions in net/http/, such as
Import ("FMT" "GOLANG.ORG/X/NET/HTTP2" "Net/http" "Net" "Time")//net/http package can be serviced by HTTP2 and opened on a service without HTTPS h2,//needs to modify Listenandserver's default H2 service type Serverhandler struct {}func (sh *serverhandler) servehttp (w http). Responsewriter, req *http. Request) {fmt. PRINTLN (req) W.header (). Set ("Server", "H2test") W.write ([]byte ("This is a HTTP2 Test Sever"))}func main () {server: = &http. server{Addr: ": 8080", Handler: &serverhandler{}, Readtimeout:5 * time. Second, Writetimeout:5 * time. Second,}//http2. Server.serveconn () S2: = &HTTP2. server{idletimeout:1 * time. Minute,} http2. Configureserver (server, S2) L, _: = Net. Listen ("TCP", ": 8080") defer l.close () fmt. PRINTLN ("Start server ...") for {RWC, err: = L.accept () if err! = Nil {fmt. Println ("Accept err:", err) Continue} go s2. Serveconn (RWC, &HTTP2. Serveconnopts{baseconfig:server})}//http. Listenandserve (": 8888", &serverhandler{})}