【go语言http2.0代码实现】

news2024/10/5 17:18:36

go语言之http2.0

  • Server
  • client

之前主要说的是基于http1.1的。然后因为http1.1存在的局限性,现在http2.0越来越流行,这里来根据go的源码来分析一下http2.0的实现。首先需要注意的是http2.0是在https的基础之上,因此推荐有https的基础或者看前面openssl https分析。首先看一下源码的实现。

Server

package main

import (
	"fmt"
	"net/http"
	"os"
	"runtime"
	"strings"
)

type textHandler struct {
	responseText string
}

func (th *textHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, th.responseText)
}

type indexHandler struct{}

func (ih *indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte("Hello"))
}

func main() {
	mux := http.NewServeMux()
	// 获取当前的目录
	_, fp, _, _ := runtime.Caller(0)
	dir := getParentDirectory(fp)

	mux.Handle("/", &indexHandler{})

	thWelcome := &textHandler{"TextHandler !"}
	mux.Handle("/text", thWelcome)
  
    // 监听服务 server.pem是签名证书 server.key是私钥
	err := http.ListenAndServeTLS(":8084", fmt.Sprintf("%s/%s", dir, "server.pem"), fmt.Sprintf("%s/%s", dir, "server.key"), mux)
	fmt.Printf("err:%v\n", err)
}
// 获取当前的目录
func getParentDirectory(directory string) string {
	return substr(directory, 0, strings.LastIndex(directory, string(os.PathSeparator)))
}
// 截取字符串
func substr(s string, pos, length int) string {
	runes := []rune(s)
	l := pos + length
	if l > len(runes) {
		l = len(runes)
	}
	return string(runes[pos:l])
}

需要注意的是这里因为之所以使用的runtime.Caller还不是使用./server.pem和./server.key的方式去,是因为往往受到运行目录的影响,并不是当前的目录,所以使用runtime.Caller去获取当前的目录。
然后ListenAndServeTLS 是在监听https的目录,第一个就是端口,然后第二个和第三个参数分别是签名的证书和生成的私钥。

client

package main

import (
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"crypto/tls"
	"net/http"
	"net/http2"
	"log"
	"os"
	"runtime"
	"strings"
	"time"
)

func main() {
	_, fp, _, _ := runtime.Caller(0)
	dir := getParentDirectory(fp)
	// 客户端证书
	clientCertFile := fmt.Sprintf("%s/%s", dir, "client.pem")
	// 客户端私钥
	clientKeyFile := fmt.Sprintf("%s/%s", dir, "client.key")
	// CA证书
	caCertFile := clientKeyFile := fmt.Sprintf("%s/%s", dir, "ca.pem")
	var cert tls.Certificate
	var err error
	if clientCertFile != "" && clientKeyFile != "" {
	// 加载客户端的私钥和证书
		cert, err = tls.LoadX509KeyPair(clientCertFile, clientKeyFile)
		if err != nil {
			log.Fatalf("Error creating x509 keypair from client cert file %s and client key file %s", clientCertFile, clientKeyFile)
			return
		}
	}
	// 读取ca的证书
	caCert, err := ioutil.ReadFile(caCertFile)
	if err != nil {
		fmt.Printf("Error opening cert file %s, Error: %s", caCertFile, err)
		return
	}
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(caCert)
    // 使用http2的Transport
	t := &http2.Transport{
		TLSClientConfig: &tls.Config{
			Certificates:       []tls.Certificate{cert},
			RootCAs:            caCertPool,
		},
	}
    // 调用
	client := http.Client{Transport: t, Timeout: 15 * time.Second}
	resp, err := client.Get("https://localhost:8084/")
	if err != nil {
		fmt.Printf("Failed get: %s\r\n", err)
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("Failed reading response body: %s\r\n", err)
	}
	fmt.Printf("Client Got response %d: %s %s\r\n", resp.StatusCode, resp.Proto, string(body))
}

func getParentDirectory(directory string) string {
	return substr(directory, 0, strings.LastIndex(directory, string(os.PathSeparator)))
}
func substr(s string, pos, length int) string {
	runes := []rune(s)
	l := pos + length
	if l > len(runes) {
		l = len(runes)
	}
	return string(runes[pos:l])
}

如果生成秘钥这些比较麻烦,也可以进行跳过,简化代码,如下:

package main

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"

	"golang.org/x/net/http2"
)

func main() {
	t := &http2.Transport{
		TLSClientConfig: &tls.Config{
		// 指定跳过校验
			InsecureSkipVerify: true,
		},
	}

	client := http.Client{Transport: t, Timeout: 15 * time.Second}
	resp, err := client.Get("https://localhost:8084/")
	if err != nil {
		fmt.Printf("Failed get: %s\r\n", err)
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("Failed reading response body: %s\r\n", err)
	}
	fmt.Printf("Client Got response %d: %s %s\r\n", resp.StatusCode, resp.Proto, string(body))
}

这里运行一下。可以看出来已经是运行成功了。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/169020.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在Microsoft Teams中发布作业

之前我们介绍了在Microsoft Teams中收发批改作业的基础使用方法。今天我们会在“发布作业”这个方面上进行详细介绍。 首先我们进入Teams的“作业”点击“创建”。 选择“作业”。 可以通过“附加”的形式发布已创建的作业文件。 可以通过选择OneDrive的形式来选取里面的文件发…

BOSS直聘依然面临监管和估值过高的风险

来源:猛兽财经 作者:猛兽财经 BOSS直聘是中国重新开放和经济复苏的受益者 由于中国已经全面放开,所以,全球各地的分析师们正在上调对中国2023年经济增长的预测。 比如CNBC的文章就提到摩根士丹利(MS)的经…

Pandas 数据结构 - Series

前言Pandas Series 类似表格中的一个列(column),类似于一维数组,可以保存任何数据类型。Series 由索引(index)和列组成,函数如下:pandas.Series( data, index, dtype, name, copy)参…

基于springboot,vue电影院售票系统

开发工具:IDEA服务器:Tomcat9.0, jdk1.8项目构建:maven数据库:mysql5.7系统用户前台和管理后台两部分,项目采用前后端分离前端技术:vue elementUI服务端技术:springbootmybatis项目功…

Java 线程的几种状态及其切换的条件

1.线程状态及其含义2.状态之间切换的条件1.线程状态及其含义 NEW(初始化): 表示创建了Thread对象,但是还没有调用start (也就是系统内核还是没有创建对应的PCB) RUNNABLE(运行): 表示可运行的.线程创建后,调用了start方法,等待CPU的调度或者正在CPU中运行. BLOCKED(阻塞): 表…

【白皮书】PROFIBUS网络诊断

PROFIBUS标准已有30多年的历史,如今已是一种成熟的数字现场总线技术。PROFIBUS通常用于工厂和过程自动化行业,也可用于食品、饮料或制药等混合行业。此外,其还适用于楼宇自动化和轨道交通等领域。可见,PROFIBUS是一种可服务于这些…

华为OD机试 - 信号发射和接收

题目描述 有一个二维的天线矩阵,每根天线可以向其他天线发射信号,也能接收其他天线的信号,为了简化起见,我们约定每根天线只能向东和向南发射信号,换言之,每根天线只能接收东向或南向的信号。 每根天线有自己的高度anth,每根天线的高度存储在一个二维数组中,各个天线…

第三方美颜sdk人脸识别的流程以及代码分析

小编曾经多次提到过人脸检测和人脸是被技术,那么这些算法在第三方美颜sdk中有用吗?答案是肯定的,不止有用,而且还非常重要。我们可以将人脸识别算法分为基础层算法与应用层算法,开头提到的人脸检测,实际上是…

Python程序设计-第1章Python程序基础

第1章Python程序基础一.预习笔记 1.1 Python简介: Python是一种面向对象的解释型计算机程序设计语言,由荷兰人Guido Van Rossum于1989年发明。Python的第一个公开发行版于1991年发行。 1.2 Python开发环境搭建: python解释器的安装&#…

2017 hypernetworks 笔记

HYPERNETWORKS 这篇文章来自谷歌的一篇文章 Introduction 这篇文章中提出了一种方法:使用一个小网络(hypernetwork),小网络的作用是给一个larger network(main network)来生成权重,这个main ne…

结构型模式

1.代理模式 提供对象的替代品或其占位符。 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理结构 抽象主题类:通过接口或抽象类声明真实主题和代理对象实现的业务方法真实主题类:实现抽象主题中的具体业务&#xff0c…

小程序API

小程序APIapi介绍api类型示例小程序api-网络请求示例合法域名npm基础应用核心步骤npm下载vant-weapp组件库核心步骤api介绍 小程序开发中,会使用到很多内置的功能,这些功能都被封装到小程序的api中了。比如 弹出提示框发送网络请求等上传文件、下载文件…

centos的官网下载和vm16虚拟机安装centos8【保姆级教程图解】

centos8的官网下载和vm16虚拟机安装centos8【保姆级图解】centos下载vm虚拟机安装centos可能出现的问题vcpu-0centos下载 centos官网:https://www.centos.org/ 进入官网后,点击Download 选择 Centos Stream 8 x86_64,并且点击进入 然后会出现国内的…

穿越寒冬 向新而行 | 智和信通2022年度年终总结大会圆满落幕

岁序更迭,新程再启,2022年在挑战与成就中谢幕。日迈月征,朝暮轮转,2023年在希望中启航。2023年1月13日,北京智和信通技术有限公司(以下简称“智和信通”)召开2022年度年终总结大会。会议全面总结…

Tp5 通过crontab 执行定时任务

声明:此处为ThInkCmf 为例:在主题中的command 中新建php文件如图在PHP文件中设置脚本名称及注释,并编写业务逻辑。protected $output ;/*** 作者:执着* 说明:定义脚本名称及添加注释* param setName:定义脚本名称* pa…

【Python百日进阶-数据分析】Day227 - plotly的子图

文章目录一、Plotly 图形工厂子图1.1 垂直图形工厂图表1.2 水平表格和图表1.3 垂直表格和图表二、表格和图表子图三、地理子图四、混合子图和 Plotly Express一、Plotly 图形工厂子图 Plotly 的 Python API 包含一个图形工厂模块,其中包含许多包装函数,…

可执行文件的装载

装载方式回顾一下操作系统的知识,程序执行的时候需要的指令和数级都必须在内存中时,程序才能正常运行,最简单的方式就是将指令和数级全部加载到内存中,这样肯定可以顺利执行,但这样的方式对内存大小来说是一个考验。因…

python中的socket网络编程

目录 一.服务端开发 1.什么是Socket网络编程 2.基于Socket完成服务端程序开发 步骤 演示 二.客户端开发 步骤 演示 一.服务端开发 1.什么是Socket网络编程 socket(简称套接字)是进程之间通信一个工具,好比现实生活中的插座,所有的家用电器要想工作都是基于…

Git系列:入门必备指令详解

Git系列:入门必备指令详解总览高频指令参考资料总览 常用指令使用流程如下图: workspace:工作区staging area:暂存区/缓存区local repository:版本库或本地仓库remote repository:远程仓库 ——引用自&…

线程学习笔记

线程 出现原因 MP3多个模块放在一个进程中,CPU处理能力,播放可能不连续;放在多个进程中,资源传递、进程维护等开销很大 进程相比于进程,地址空间直接共享 定义 线程是进程的执行流程,除了线程&#xf…