
相关阅读:
Start
前边两章讲了很多HTTP/2概念性的东西,看起来比较无趣,从这次开始,我们从一些实际用途开始讲起。
本次讲一个非常简单的功能,然后把其内部实现串一下。
这次要实现的功能非常简单,就是一个http2的server,对客户端的请求,只返回一个header信息,并且保持连接,以便在后续任何时候进行一些其他的响应操作。目前看起来这个场景可能没有太大作用,其实HTTP/2做为一个超文本传输协议,目前我们能想到的应用场景还都是普通的web业务,但是老外们的思路就比较广,已经把一些HTTP/2的特性在特定的场景发挥出来了,比如 Amazon的Alexa,Apple的APNS 等。这次实现的这个小功能,就是Alexa里用到的一小部分.
Amazon的avs(Alexa Voice Service)通过HTTP/2实现了全双工的传输功能,其下行功能就用到了这块,Alexa跟avs建立链接后,客户端会发起一个GET /v20160207/directives的请求,服务端接受请求后,返回一个200的头信息,并hold住链接,后续使用该链接通过Server Push功能给客户端主动发送指令。
本次开始,我们先不管Server Push,先从发送Header这个小功能开始吧。
HTTP/2在GO语言的实现中没有支持h2c,所以我们必须使用带证书的加密方式,那么首先需要有一张证书。
我们可以使用openssl自己生成一张:
openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt
然后按提示随便输入一些内容就可以得到两个文件,server.key和server.crt,其实就是相当于私钥和公钥。当然这个证书是不能在互联网上正常流通使用的,因为证书是自己签发的,没有人给你做担保,能确认这个证书跟它所标识的内容提供方是匹配的。所以我们在做请求测试的时候,需要客户端忽略证书校验才可以。
服务端GO示例的代码如下:
package main
import (
"log"
"net/http"
)
func main() {
http.HandleFunc("/header", func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("X-custom-header", "custom header")
w.WriteHeader(http.StatusNoContent)
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
select {}
})
log.Println("start listen on 8080...")
log.Fatal(http.ListenAndServeTLS(":8080", "server.crt", "server.key", nil))
}
服务运行起来后我们在一个较新的支持HTTP/2的curl命令下执行:
curl "https://localhost:8080/header" -k -i --http2
-k 参数表示忽略证书校验,避免客户端拿到证书后校验不通过而拒绝链接-i 参数表示显示返回的header信息--http2 表示启用http/2,这个参数也可以不带,因为客户端支持的话,会优先使用http/2去链接,服务端不支持的时候降级到http/1.1

这样就实现了只返回了一个header信息,并且链接没有断开。
我们再通过前边介绍过的h2c来看下请求的效果:

可以看到返回的只有一个Header信息,并且是没有END_STREAM标记的。
本次的实践内容到这里就可以结束了,最终实现的代码很简单,但是为什么这样可以实现呢,在缺少相关资料的情况下,很难知道这样做是可以实现该目的的,那么接下来就从Go语言中对HTTP/2的实现来一探究竟吧: