当前位置: 首页 > news >正文

Golang net/http标准库常用方法(三)

大家好,针对Go语言 net/http 标准库,将梳理的相关知识点分享给大家~~
围绕 net/http 标准库相关知识点还有许多章节,请大家多多关注。
文章中代码案例只有关键片段,完整代码请查看github仓库:https://github.com/hltfaith/go-example/tree/main/net-http

本章节案例,请大家以 go1.16+ 版本以上进行参考。

net/http标准库系列文章

  • Golang net/http标准库常用请求方法(一)
  • Golang net/http标准库常用方法(二)
  • Golang net/http标准库常用方法(三)

本节内容

  • ProxyFromEnvironment() 函数
  • ProxyURL() 函数
  • Serve() 函数
  • ServeContent() 函数
  • DetectContentType() 函数
  • MaxBytesReader() 函数

ProxyFromEnvironment()

ProxyFromEnvironment()函数,用于读取所在环境的环境变量返回代理地址。比如环境变量HTTP_PROXYHTTPS_PROXYNO_PROXY,如果在 NO_PROXY 排除的地址则不进行代理。
代理地址格式可以是完整的URL,也可以是host[:port]。支持 HTTPHTTPSSOCKS5代理。
如果环境中未定义代理,或者NO_PROXY定义的给定请求不应使用代理,则返回nil URLnil错误。如果 req.URL.Host 地址为 localhost 加或没加端口,都会返回 nil 错误。
函数原型

func ProxyFromEnvironment(req *Request) (*url.URL, error)

函数使用
proxyfromenvironment.go

func main() {os.Setenv("HTTP_PROXY", "http://127.0.0.1:12345")req, err := http.NewRequest("GET", "http://example.com", nil)if err != nil {panic(err)}url, err := http.ProxyFromEnvironment(req)if err != nil {panic(err)}fmt.Println(url)
}

案例中 http.ProxyFromEnvironment(req) 仅会把读取环境变量 HTTP_PROXY 的代理地址,在我们使用 http.NewRequest() 请求时,不会使用代理请求。
下面通过 ProxyURL() 函数案例,发起代理请求。

ProxyURL()

ProxyURL() 作用是返回一个代理函数主要用于在 Transport{} 类型中,其参数是代理地址。
函数原型

func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error)

举例:使用代理发送 HTTP 请求。
proxyurl.go

func main() {url, err := url.Parse("http://188.68.176.2:8080")if err != nil {panic(err)}client := http.Client{Transport: &http.Transport{Proxy:           http.ProxyURL(url),TLSClientConfig: &tls.Config{InsecureSkipVerify: true},},}res, err := client.Get("http://baidu.com")if err != nil {panic(err)}b, _ := httputil.DumpRequest(res.Request, false)fmt.Println(string(b))
}

上述例子中, 将代理函数ProxyURL(url)通过Transport{}类型封装好后,向目标服务发送GET请求。
Client{}Transport{}类型后续文章将详细讲解。

注:代理地址,可以参考 https://www.kuaidaili.com/free/fps/ 用于测试使用。

上面案例,也可以将 http.ProxyURL() 函数改成 ProxyFromEnvironment() 用环境变量的方式。
proxyurl2.go

func main() {url, err := url.Parse("http://google.com")if err != nil {panic(err)}os.Setenv("HTTP_PROXY", "http://127.0.0.1:7890")client := http.Client{Transport: &http.Transport{Proxy:           http.ProxyFromEnvironment,TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // 跳过https},}req := http.Request{Method: "GET",URL:    url,Header: map[string][]string{"Proxy-Connection": {"keep-alive"},},}res, err := client.Do(&req)if err != nil {panic(err)}defer res.Body.Close()
}

这里是通过我本地环境的代理VPN所监听的端口 http://127.0.0.1:7890

下面我通过抓包,大家可以看到执行代理请求的时候源端口 50130是我们请求端,访问的谷歌网站目的端已经变成了 http://127.0.0.1:7890 地址也是我们的代理端,后面的响应也是由代理端给我们请求回应数据包。

Serve()

Serve() 函数,接收监听 HTTP 连接请求,为每个连接创建一个新goroutinegoroutine读取请求,然后调用处理程序来回复它们。
官方建议 handlernil类型, 则默认使用 DefaultServerMux 全局锁机制。 (可以参考上篇文章中有所介绍)
只有当 Listener 返回tls的时候,才支持HTTP/2协议。
Serve() 函数返回非 nil 的报错。
函数原型

func Serve(l net.Listener, handler Handler) error

Serve()函数实际上是调用的 Server{} 类型中封装的一个方法。

func Serve(l net.Listener, handler Handler) error {srv := &Server{Handler: handler}return srv.Serve(l)
}

例如,上篇文章中介绍的 ListenAndServe()ListenAndServeTLS() 方法它们最终执行都是 Server{}类型中的 Serve() 方法。

函数使用
serve.go

func main() {ln, err := net.Listen("tcp", ":8080")if err != nil {panic(err)}http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {io.WriteString(w, "帽儿山的枪手!\n")})log.Panicln(http.Serve(ln, nil))
}

ServeContent()

ServeContent() 函数,使用ReadSeeker所读取的内容回复给用户请求。

ServeContentio.Copy更好的是,他能够合适的处理一批请求,设置MIME类型,并且能够处理文件是否修改的请求。

如果响应的内容类型头没有设置,该函数首先会尝试从文件的文件扩展名推断文件类型。 如果推断不出来,则会读取文件的第一个块并传送给DetectContentType来检测类型。

文件名称也可以不使用。 如果文字名称为空,则服务器不会传送给响应。 如果修改时间不为0,ServeContent会把它放在服务器响应的Last-Modified头里面。 如果客户端请求中包含了If-Modified-Since头,ServeContent会使用modtime来判断是否把内容传给客户端。
contentSeek方法必须能够工作。 ServeContent通过定位到文件结尾来确定文件大小。 *os.File中实现了io.ReadSeeker接口。

函数原型

func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time, content io.ReadSeeker)
  • 参数 w 服务器响应
  • 参数 req 客户端请求
  • 参数 name 文件名称
  • 参数 modtime 文件的修改时间
  • 参数 content 文件的内容,必须实现 io.ReadSeeker 这个接口中的方法

下面案例使用 ServeContent() 函数实现文件下载功能。
servecontent.go

func main() {http.HandleFunc("/download", func(w http.ResponseWriter, r *http.Request) {file := "servecontent.go"fileBytes, err := ioutil.ReadFile(file)if err != nil {panic(err)}mime := http.DetectContentType(fileBytes)fileSize := len(string(fileBytes))w.Header().Set("Content-Type", mime)w.Header().Set("Content-Disposition", "attachment; filename="+file)w.Header().Set("Content-Length", strconv.Itoa(fileSize))http.ServeContent(w, r, file, time.Now(), bytes.NewReader(fileBytes))})log.Fatal(http.ListenAndServe(":8080", nil))
}

首先通过 DetectContentType()函数获取了文件的 MIME 类型,然后将文件转换为 Byte 类型传入 ServeContent() 函数中实现下载功能。
结合上篇文章中介绍的 ServeFile()函数它实现起来更简洁仅需要一行代码实现文件下载,但前提需要知道文件上下文路径。
ServeContent() 函数更适用于当你只能拿到 byte[] 数据时,可以优先使用它。

DetectContentType()

DetectContentType() 该函数实现了一个算法,用来检测指定的数据是否符合该标准http://mimesniff.spec.whatwg.org

最多需要数据的前512个字节,DetectContentType()会返回一个有效的MIME类型。 如果它不能够识别数据,将会返回"application/octet-stream"
函数原型

func DetectContentType(data []byte) string

函数使用

func main() {// image/pngfmt.Println(http.DetectContentType([]byte("\x89PNG\x0D\x0A\x1A\x0A")))// image/jpegfmt.Println(http.DetectContentType([]byte("\xFF\xD8\xFF")))
}

注:一些类型的识别,可以参考go源码测试用例。

MaxBytesReader()

MaxBytesReader() 函数,用来保护服务器端,以避免客户端偶然或者恶意发送的长数据请求导致的服务端资源的浪费。

MaxBytesReader()io.LimitReader函数很像。但是它被设计来设置接收的请求体的最大大小。 跟io.LimitReader不同MaxBytesReader()的返回值是一个ReadCloser,当读取超过限制时会返回non-nil错误。 并且当它调用关闭方法的时候会把潜在的读取者(函数/进程)也关闭掉。

函数原型

func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser
  • 参数 w服务器响应
  • 参数 r可以指向 req.Body
  • 参数 n限制大小

案例,限制客户端上传数据为10个字节。
maxbytesreader.go

func main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {r.Body = http.MaxBytesReader(w, r.Body, 10)_, err := io.Copy(ioutil.Discard, r.Body)if err != nil {panic(err)}io.WriteString(w, "200\n")})log.Fatal(http.ListenAndServe(":8080", nil))
}

下面我们通过 curl 命令模拟客户端请求, 其中body内容已经超出了10个字节

root@hc:~# curl --location --request POST 'http://127.0.0.1:8080' \
--header 'Content-Type: application/json' \
--data-raw '{"t": "1234567890"
}'

请求完成后,看到服务端已经提示 请求Body过大

技术文章持续更新,请大家多多关注呀~~

搜索微信公众号,关注我【 帽儿山的枪手 】

相关文章:

Golang net/http标准库常用方法(三)

大家好,针对Go语言 net/http 标准库,将梳理的相关知识点分享给大家~~ 围绕 net/http 标准库相关知识点还有许多章节,请大家多多关注。 文章中代码案例只有关键片段,完整代码请查看github仓库:https://github.com/hltfa…...

24校招总结

个人背景 本科:三本通信专业 硕士:B区双非计算机硕 今年2月签了东南沿海二线城市某公司C游戏服务端开发 我同学大部分都是去电网,大专老师,气象局事业编……就我这个是纯牛马了。 离收到Offer3个月了,前段时间参加…...

PHP APCu缓存使用与避坑

APCu 极简概括: PHP 的开源内存缓存扩展,类比Redis,但是一般都用Redis,所以APCu用的很少。官方文档:https://www.php.net/manual/zh/apcu.configuration.php解决问题:类比Redis做缓存组件,提升…...

mybatis xml

delete from t_enterprise_output_value where output_id IN #{outputId} 批量插入 功能&#xff1a;单个或批量插入数据&#xff0c;若数据已存在&#xff0c;则忽略 <insert id"saveBatchIgnoreInto" parameterType"java.util.List">insert igno…...

“不是我兄弟”!刘强东内部“狼性训话”流出!

今天&#xff0c;京东创始人刘强东5月24日的线上讲话流出。 在这次线上讲话中&#xff0c;刘强东首先宣布为全体采销员工涨薪20%—100%&#xff0c;随后进行了一番“狼性训话”。往期报道可戳&#xff1a;刘强东怒了&#xff1a;“不是我兄弟”&#xff01; 刘强东在讲话中指…...

函数调用时长的关键点:揭秘参数位置的秘密

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、默认参数的秘密 示例代码 二、关键字参数与位置参数的舞蹈 示例代码 总结 一、默认参…...

【数据分析面试】54.员工信息(HR)数据库搭建

题目 由于发展需求&#xff0c;进一步提高公司人员统筹管理的能力&#xff0c;公司决定要重新升级人力数据管理系统。 现在&#xff0c;你的任务是为公司重新设计和搭建一个员工信息数据库。 提示&#xff1a;考虑HR管理系统的功能&#xff0c;比如人员信息、入职时间、离职…...

通过JavaScript本地存储数据

文章目录 本地存储本地存储分类 - localStorage本地存储分类 - sessionStorage存储复杂数据类型解决方法 本地存储 数据存储在用户浏览器中设置、读取方便、甚至页面刷新都不丢失数据容量较大&#xff0c;sessionStorage和localStorage约5M左右 本地存储分类 - localStorage …...

CTF-web-攻防世界-3

1、inget (1)、进入网站&#xff0c;提示传入id值 (2)、用一些闭合方式&#xff0c;返回都一样。 (3)、尝试万能密码。获得flag 2、mfw (1)、页面没有什么特殊的异常&#xff0c;使用dirsearch进行目录扫描&#xff0c;有一些.git文件。看样子是.git文件泄露。 使用githa…...

【附代码案例】深入理解 PyTorch 张量:叶子张量与非叶子张量

在 PyTorch 中&#xff0c;张量是构建神经网络模型的基本元素。了解张量的属性和行为对于深入理解模型的运行机制至关重要。本文将介绍 PyTorch 中的两种重要张量类型&#xff1a;叶子张量和非叶子张量&#xff0c;并探讨它们在反向传播过程中的行为差异。 叶子张量与非叶子张…...

TypeScript 学习笔记(七):TypeScript 与后端框架的结合应用

1. 引言 在前几篇学习笔记中,我们已经探讨了 TypeScript 的基础知识和在前端框架(如 Angular 和 React)中的应用。本篇将重点介绍 TypeScript 在后端开发中的应用,特别是如何与 Node.js 和 Express 结合使用,以构建强类型、可维护的后端应用。 2. TypeScript 与 Node.js…...

Linux基础知识点总结!超详细

Linux 的学习对于一个IT工程师的重要性是不言而喻的&#xff0c;学好它是工程师必备修养之一。 Linux 基础 操作系统 操作系统Operating System简称OS&#xff0c;是软件的一部分&#xff0c;它是硬件基础上的第一层软件&#xff0c;是硬件和其它软件沟通的桥梁。 操作系统…...

中小学校活动怎样投稿给媒体报道宣传?

身为一名学校老师,同时承担起单位活动向媒体投稿的宣传重任,我深知每一次校园活动背后的故事,都承载着师生们的辛勤汗水与教育的无限可能。起初,我满怀着对教育的热情,希望通过文字传递校园的温暖与光芒,却在投稿的道路上遇到了前所未有的挑战。 最初,我选择了最传统的路径——…...

Python代码:十七、生成列表

1、题目 描述&#xff1a; 一串连续的数据用什么记录最合适&#xff0c;牛牛认为在Python中非列表&#xff08;list&#xff09;莫属了。现输入牛牛朋友们的名字&#xff0c;请使用list函数与split函数将它们封装成列表&#xff0c;再整个输出列表。 输入描述&#xff1a; …...

C++ 程序的基本要素

一 标识符 程序中变量、类型、函数和标号的名称称标识符。 a,b,name,int,char,main,void等。 系统已有的标识符称为关键字。 常见关键字 using,namespace,void,return; int,float,double,char,bool,signed,unsignex, long,short,const,true,false,sizeof if,else,for,do,whil…...

藏汉翻译工具有哪些?这三款工具简单好用

藏汉翻译工具有哪些&#xff1f;在全球化日益加剧的今天&#xff0c;语言交流成为连接不同文化、促进民族间沟通与理解的重要桥梁。藏汉翻译工具作为推动藏汉文化交流的得力助手&#xff0c;其在促进民族团结、增进相互理解方面的作用愈发凸显。本文将为您盘点市面上主流的藏汉…...

three.js官方案例webgl_loader_fbx.html学习

目录 1.1 添加库引入 1.2 添加必要的组件scene,camera,webrenderer等 1.3 模型加载 1.4 半球光 1.5 动画 1.6 换个自己的fbx模型 1.7 fbx模型和fbx动画关联 1.7 html脚本全部如下 1.8 fbx.js全部脚本如下 1.1 添加库引入 import * as THREE from three; import Stats …...

51单片机-实机演示(单多个数码管)

仿真链接&#xff1a; http://t.csdnimg.cn/QAPhx 目录 一.引脚位置 二.多个显示 三 扩展 一.引脚位置 注意P00 - >A ; 这个多个的在左边,右边的A到B是控制最右边那个单个的. 接下来上显示单个的代码 #include <reg52.h> #include <intrins.h> #define u…...

Pytorch深度学习实践笔记10(b站刘二大人)

&#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;pytorch深度学习 &#x1f380;CSDN主页 发狂的小花 &#x1f304;人生秘诀&#xff1a;学习的本质就是极致重复! 《PyTorch深度学习实践》完结合集_哔哩哔哩_bilibi…...

QT5.15.2及以上版本安装

更新时间&#xff1a;2024-05-20 安装qt5.15以上版本 系统&#xff1a;ubuntu20.04.06 本文安装&#xff1a;linux-5.15.2 下载安装 # 安装编译套件g sudo apt-get install build-essential #安装OpenGL sudo apt-get install libgl1-mesa-dev# 下载qt安装器 https://downl…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...