Golang сделал это относительно рано в http/2, но по историческим причинам API сбивает с толку, и многие онлайн-студенты жалуются.
Я запишу здесь, как правильно реализовать клиент и сервер HTTP/2.
Протокол HTTP/2
Рукопожатие протокола HTTP/2 делится на два способа: один называется h2, а другой — h2c.
h2 требует шифрования TLS.Во время рукопожатия TLS будет завершено согласование протокола HTTPS/2.Если согласование не удается (например, клиент не поддерживает его или сервер не поддерживает), HTTPS/1 будет используется для продолжения последующего общения.
h2c использует не TLS, а дополнительный цикл рукопожатия на основе протокола HTTP для завершения обновления до протокола HTTP/2, что обычно не рекомендуется.
Стандартная библиотека Go
http-библиотека GO по умолчанию поддерживает протокол HTTP/2, и пока мы используем TLS, функция HTTP/2 будет включена по умолчанию.
Библиотека http не поддерживает использование h2c при разработке API, но поощряет использование h2.
Пока мы используем TLS, библиотека http по умолчанию будет выполнять согласование HTTPS/2, а если согласование не удастся, она выродится в HTTPS/1.
Что смущает многих разработчиков, так это то, что когда мы хотим сделать некоторые дополнительные настройки для http-клиента или сервера, они переопределяют поведение библиотеки http по умолчанию, что приводит к невозможности включения протокола HTTP/2.
Ниже я расскажу, как убедиться, что протокол HTTP/2 включен.
Сервер
Мы явно должны использовать режим h2, что означает жертвование временем шифрования TLS, но в обмен на удобство HTTP/2.
Сделать сертификат
Сначала нам нужно сделать сертификат и закрытый ключ для сервера, где сертификат будет отправлен обратно клиенту при получении запроса.
Сертификат самоподписан нами, а стороннего ЦС для проверки нет, поэтому клиенту необходимо отключить функцию проверки валидности сертификата.
1,生成服务端私钥
openssl genrsa -out default.key 2048
2,生成服务端证书
openssl req -new -x509 -key default.key -out default.pem -days 3650
default.key — закрытый ключ, а default.pem — сертификат.
свидетельство о проверке
Поскольку мы являемся сертификатом, подписанным в формате X509, поэтому программа готова сначала выполнить проверку валидности:
// TLS证书解析验证
if _, err = tls.LoadX509KeyPair(G_config.ServerPem, G_config.ServerKey); err != nil {
return common.ERR_CERT_INVALID
}
После подтверждения того, что сертификат действителен, мы, наконец, передаем сертификат и закрытый ключ через serverTLS, чтобы запустить службу HTTPS/2:
// HTTP/2 TLS服务
server = &http.Server{
ReadTimeout: time.Duration(G_config.ServiceReadTimeout) * time.Millisecond,
WriteTimeout: time.Duration(G_config.ServiceWriteTimeout) * time.Millisecond,
Handler: mux,
}
// 监听端口
if listener, err = net.Listen("tcp", ":" + strconv.Itoa(G_config.ServicePort)); err != nil {
return
}
// 拉起服务
go server.ServeTLS(listener, G_config.ServerPem, G_config.ServerKey)
Помимо использования ServeTLS для запуска сервера, поддерживающего функцию HTTPS/2, вы также можете использоватьhttp2.ConfigureServerчтобы включить функцию HTTPS/2 для http.Server и использовать Serve напрямую для запуска службы.
клиент
Самое главное для клиента — настроить транспорт, так называемый транспорт — это базовый диспетчер соединений, включая возможности обработки протокола.
Поскольку у нас много потребностей в настройке конфигурации клиента, мы сами сгенерировали транспорт вместо встроенного транспорта:
transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true,}, // 不校验服务端证书
MaxIdleConns: G_config.GatewayMaxConnection,
MaxIdleConnsPerHost: G_config.GatewayMaxConnection,
IdleConnTimeout: time.Duration(G_config.GatewayIdleTimeout) * time.Second, // 连接空闲超时
}
Конфигурация TLS объявляет InsecureSkipVerify=true, что означает, что ЦС не проверяет действительность сертификата.
Подобно серверу, поскольку мы не используем встроенный клиентский транспорт, нам нужно использоватьhttp2.ConfigureTransportЧтобы включить функцию HTTPS/2:
// 启动HTTP/2协议
http2.ConfigureTransport(transport)
Наконец, настройте транспорт к клиенту, который отвечает за базовое соединение и управление протоколом:
// HTTP/2 客户端
gateConn.client = &http.Client{
Transport: transport,
Timeout: time.Duration(G_config.GatewayTimeout) * time.Millisecond, // 请求超时
}
Наконец
Сначала поймите разницу между h2 и h2c, а потом объясните, что язык Go рекомендует использовать h2.
Наконец, когда мы не используем конфигурацию http по умолчанию, нам нужно перенастроить, чтобы включить функцию HTTP2/S через http2.ConfigureXXX.