19.2 HTTP客户端-定制HTTP请求、调试HTTP、响应超时

1. 定制HTTP请求

如果需要对向服务器发送的HTTP请求做更多超越于默认设置的定制化。

  • client := http.Client{}
    • 使用net/http包提供的导出类型Client,创建一个表示客户端的变量。
  • request, err := http.NewRequest("GET", "https://ifconfig.io/ip", nil) 
    • 调用net/http包提供的导出函数NewRequest,构建一个HTTP请求。
    • 参数解析:请求类型,目标url;返回1个request变量。
  • response, err := client.Do(request)
    • 用所创建的客户端发送所构建的HTTP请求,并获取响应。

用这种方法可以单独设置请求头基本身份验证cookies等请求参数。

一般而言,除非要完成的任务非常简单,否则推荐使用这种定制化方法。

// 定制HTTP请求
// 如果快捷方法产生的简单GET请求不足以满足对请求报文
// 做进一步控制的需要,则可以使用自定义的HTTP客户端
package main
import ("fmt""io/ioutil""log""net/http"
)func main() {client := http.Client{}request, err := http.NewRequest("GET", "https://ifconfig.io/ip", nil)if err != nil {log.Fatal(err)}response, err := client.Do(request)if err != nil {log.Fatal(err)}defer response.Body.Close()resBody, err := ioutil.ReadAll(response.Body)if err != nil {log.Fatal(err)}fmt.Printf("%s", resBody)
}
// 打印输出:
xxx.xxx.xxx.xxx 显示客户端ip,已隐去

 2. 调试HTTP

Go语言标准库的net/http/httputil包提供了一些方法,可用于调试往返于客户端和服务器之间的HTTP请求响应

  • 打印请求包,下面2个函数均返回关于“请求”或“响应”的字节切片,转为为字符串格式即可打印显示。
    • debugRequest, err := httputil.DumpRequestOut(request, true)
    • fmt.Printf("%s", debugRequest)
  • 打印响应包
    • debugResponse, err := httputil.DumpResponse(response, true)
    • fmt.Printf("%s", debugResponse)

如果我们希望仅在调试环节打印这些信息,那么可以将DEBUG设置为1个环节变量或配置变量,通过os包Getenv函数用于获取环境变量的值,可据此判断是否打印调试信息。

  • debug := os.Getenv("DEBUG")
// 调试HTTP请求
// net/http/httputil包的DumpRequestOut和DumpResponse函
// 数,可用于在调试过程中查看HTTP请求和响应,帮助查找BUG
package mainimport ("fmt""io/ioutil""log""net/http""net/http/httputil""os"
)func main() {debug := os.Getenv("DEBUG")client := http.Client{}request, err := http.NewRequest("GET", "https://ifconfig.io/ip", nil)if err != nil {log.Fatal(err)}request.Header.Add( // 通过设置请求头,设置了可接受的响应内容类型为json"Accept", "application/json")if debug == "1" {	// 打印请求debugRequest, err :=httputil.DumpRequestOut(request, true)if err != nil {log.Fatal(err)}fmt.Printf("%s", debugRequest)}response, err := client.Do(request)if err != nil {log.Fatal(err)}defer response.Body.Close()if debug == "1" {	// 打印响应debugResponse, err :=httputil.DumpResponse(response, true)if err != nil {log.Fatal(err)}fmt.Printf("%s", debugResponse)}resBody, err := ioutil.ReadAll(response.Body)if err != nil {log.Fatal(err)}fmt.Printf("%s", resBody)
}
// 打印输出:
GET /ip HTTP/1.1
Host: ifconfig.io
User-Agent: Go-http-client/1.1
Accept: application/json
Accept-Encoding: gzipHTTP/2.0 200 OK
Content-Length: 13
Alt-Svc: h3-24=":443"; ma=86400, h3-23=":443"; ma=86400
Cf-Cache-Status: DYNAMIC
Cf-Ray: 562461317d37d342-LAX
Content-Type: text/plain; charset=utf-8
Date: Sun, 09 Feb 2020 08:12:40 GMT
Expect-Ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
Set-Cookie: __cfduid=d9ad8e7d64d78d19d075953bebfb13afa1581235960; expires=Tue, 10-Mar-20 08:12:40 GMT; path=/; domain=.ifconfig.io; HttpOnly; SameSite=Laxxxx.xxx.xxx.xxx	客户端ip,已隐去
xxx.xxx.xxx.xxx

 3. 响应超时

客户端向服务器发送请求后,完全无法知道服务器会在多长时间内返回响应。

在系统的底层,有太多因素会对响应时间构成影响。

  • 在客户端一侧:
    • DNS查找速度
    • 创建TCP套接字的速度
    • 与服务器建立TCP连接的速度
    • TLS握手的速度(如果使用HTTPS)
    • 向服务器发送数据的速度
  • 在服务器一侧:
    • 重定向的速度
    • 业务处理的速度
    • 向客户端发送数据的速度

默认方式创建的客户端没有对响应设置超时,这意味着:

  • 如果服务器很久甚至永远没有向客户端返回响应,客户端将一直等待
  • 维持这条连接的内存和表示这个套接字的文件描述符,也将一直存在
  • 如果发出的多个请求都是这种情况,那么客户端的资源将会很快耗尽

建议为客户端设置响应超时,一旦超过时间还没有收到响应,即宣告错误

  • client := http.Client{Timeout: 1 * time.Second}

        在声明http.Client变量对象时,设置其Timeout字段值,例如设置响应超 时1秒钟 。

  • response, err := client.Do(request)

        继续使用client.Do发送请求,如果超过一秒钟还没收到来自服务器的响应,则返回错误。

// 处理响应超时
// HTTP客户端在向服务器发送请求后,完全无法知道何时能收到对方的响应。
// 建议设置一个超时时间,如果在指定的时间内没有收到响应,则返回错误
package main
import ("fmt" "io/ioutil" "log" "net/http" "net/http/httputil" "os" "time" 
)
func main() {debug := os.Getenv("DEBUG")client := http.Client{Timeout: 1 * time.Second}request, err := http.NewRequest("GET", "https://ifconfig.io/ip", nil)if err != nil {log.Fatal(err)}if debug == "1" {debugRequest, err :=httputil.DumpRequestOut(request, true)if err != nil {log.Fatal(err)}fmt.Printf("%s", debugRequest)}response, err := client.Do(request)if err != nil {log.Fatal(err)}defer response.Body.Close()if debug == "1" {debugResponse, err :=httputil.DumpResponse(response, true)if err != nil {log.Fatal(err)}fmt.Printf("%s", debugResponse)}resBody, err := ioutil.ReadAll(response.Body)if err != nil {log.Fatal(err)}fmt.Printf("%s", resBody)
}
// 打印输出:
2020/02/09 14:21:08 Get https://ifconfig.io/ip: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

使用Transport可以更精细化地控制超时,甚至为传输的每个阶段设置超时。此时,我们需要填充client结构体中的Transport字段,该字段值是由一个http导出类型(公有类型)Transport所创建的结构体变量,该结构体可包含多个字段,通过每个字段为传输的每个阶段设置单独的超时时间。

  • dl := net.Dialer{
  •     Timeout:   30 * time.Second,
  •     KeepAlive: 30 * time.Second,
  • }
  • tr := http.Transport{
  •     DialContext:           dl.DialContext,
  •     TLSHandshakeTimeout:   10 * time.Second,
  •     IdleConnTimeout:       90 * time.Second,
  •     ResponseHeaderTimeout: 10 * time.Second,
  •     ExpectContinueTimeout:  1 * time.Second,
  • }
  • client := http.Client{Transport: &tr}
// 精细化控制超时
// 使用Transport可以更精细化地控制超时,甚 
// 至为HTTP传输的每个阶段设置独立的超时
package mainimport ("fmt""io/ioutil""log""net""net/http""net/http/httputil""os""testing""time"
)func TestFineResponseTimeout(t *testing.T) {debug := os.Getenv("DEBUG")dl := net.Dialer{Timeout:   30 * time.Second,KeepAlive: 30 * time.Second,}tr := http.Transport{DialContext:           dl.DialContext,TLSHandshakeTimeout:   10 * time.Second,IdleConnTimeout:       90 * time.Second,ResponseHeaderTimeout: 10 * time.Second,ExpectContinueTimeout: 1 * time.Second,}client := http.Client{Transport: &tr}request, err := http.NewRequest("GET", "https://ifconfig.io/ip",nil)if err != nil {log.Fatal(err)}if debug == "1" {debugRequest, err :=httputil.DumpRequestOut(request, true)if err != nil {log.Fatal(err)}fmt.Printf("%s", debugRequest)}response, err := client.Do(request)if err != nil {log.Fatal(err)}defer response.Body.Close()if debug == "1" {debugResponse, err :=httputil.DumpResponse(response, true)if err != nil {log.Fatal(err)}fmt.Printf("%s", debugResponse)}resBody, err := ioutil.ReadAll(response.Body)if err != nil{log.Fatal(err)}fmt.Printf("%s",resBody)
}
// 打印输出:
2020/02/09 16:39:39 Get https://ifconfig.io/ip: dial tcp: lookup ifconfig.io: no such host //手动断网导致访问失败

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

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

相关文章

OpenCV图像算术位运算

一 图像相加 import cv2 import numpy as npgirlcv2.imread(./2037548.jpg)#图像的加法运算就是矩阵的加法运算 #因此加法运算的两张图必须是相等的print(girl.shape)imgnp.ones((1920,1080,3),np.uint8)*50 cv2.imshow(girl,girl) resultcv2.add(girl,img) cv2.imshow(result…

QQ 邮箱绑定校园邮箱失败但 Coremail 论客绑定成功

目录 1 查看本校学生邮件系统官网 2 QQ 邮箱绑定失败 3 Coremail 论客绑定成功 前言:个人觉得每次查看校园邮箱都要打开电脑很不方便,遂决定绑定到 QQ 邮箱 APP 上。 1 查看本校学生邮件系统官网 仅针对我们学校,登录页面给出了邮件服…

【软件基础】Linq优化双重for循环、批量写入Excel以提升程序运行速度、常见代码优化方法

文章目录 前言一、使用Linq优化双重for循环二、使用Office插件批量写入Excel三、常见代码优化方法1、字符串拼接2、使用 LINQ 查询3、频繁访问数据库4、频繁使用大对象图5、未使用索引进行查找6、频繁的装箱和拆箱操作7、使用递归导致堆栈溢出8、频繁的文件I/O操作9、未使用并行…

Python 学习 第二册 对第一册的一些补充

-----用教授的方法学习 1.一些常见函数 函 数 描 述 abs(number) 返回指定数的绝对值 bytes(string, encoding[, errors]) 对指定的字符串进行编码,并以指定的方式处理错误 cmath.sqrt(number) 返回平方根;可用于负数 float(object) 将字符…

k8s-kubernetes常用命令,服务部署,可视化控制台安装及token的生成

上一篇文章介绍了怎么安装kubernetes,现在我们来学习下kubernetes的常用命令 我们直接通过部署可视化控制台kubernetes-dashboard来顺便学习下kubernetes的常用命令及服务的部署 kubernetes dashboard部署 执行下面的命令下载及安装 kubernetes dashboard kubectl apply -f…

数据分析------统计学知识点(五)

回归算法 想象一下,你和朋友在讨论:大学生活中,每天学习的时间是否真的能影响期末成绩?这个问题看似简单,实则包含了一个潜在的关系:学习时间与成绩之间的联系。我们想要知道,增加学习时间是否会提高成绩,以及这种提…

MYSQL 索引下推 45讲

刘老师群里,看到一位小友 问<MYSQL 45讲>林晓斌的回答 大意是一个组合索引 (a,b,c) 条件 a > 5 and a <10 and b123, 这样的情况下是如何? 林老师给的回答是 A>5 ,然后下推B123 小友 问 "为什么不是先 进行范围查询,然后在索引下推 b123?" 然后就…

热门开源大模型项目推荐

一&#xff1a;开源大模型热门项目推荐 NNI&#xff1a;由微软发布的开源AutoML工具包&#xff0c;支持神经网络超参数调整。最新版本对机器学习生命周期的各个环节做了全面支持&#xff0c;包括特征工程、神经网络架构搜索(NAS)、超参调优和模型压缩。适用于各种机器学习项目&…

C++240613

自由发挥登录窗口的应用场景&#xff0c;实现一个登录窗口界面 要求&#xff1a;每行代码都有注释 #include "my_widget.h"My_Widget::My_Widget(QWidget *parent): QWidget(parent) {//设置窗口的标题this->setWindowTitle("真爱生命&#xff0c;远离赌博&…

2024大交通场景空间策展洞察报告

来源&#xff1a;邻汇吧&万一商管 近期历史回顾&#xff1a; 2024国内工商业储能市场研究报告.pdf 2023幸福企业白皮书.pdf 2024年欧亚地区移动经济报告.pdf 内容供应链变革 2023人工智能与首席营销官&#xff08;CMO&#xff09; AI科技对PC产业的影响.pdf 金融业数据应用…

智能合约漏洞类型

Are We There Yet? Unraveling the State-of-the-Art Smart Contract Fuzzers | Proceedings of the IEEE/ACM 46th International Conference on Software Engineering

PySide6实现pdf转化为word和长图片

目录 一:实现思路 二:实现过程 三:完整代码和实现 一:实现思路 最近在使用wps,发现wps中使用pdf转化为长图片还需要收费,这么不地道。就想自己能不能用程序实现这种功能的。还好python在自动化办公领域比较强悍,对文档操作也是得心应手。因此记录下用python实现pdf转…

Java求职季 必备知识脑图 收藏起来 !!!

Java初中级知识脑图 面试超实用 1.Git 下载链接 导图下载地址 &#xff1a; https://mm.edrawsoft.cn/mobile-share/index.html?uuid31d00742157057-src&share_type1 2.JUC 下载链接 https://mm.edrawsoft.cn/mobile-share/index.html?uuid6c0be457444921-src&s…

计算机网络 —— 应用层(DNS域名系统)

计算机网络 —— 应用层&#xff08;DNS域名系统&#xff09; 什么是DNS域名的层次结构域名分类 域名服务器的分类域名解析方式递归查询&#xff08;Recursive Query&#xff09;迭代查询&#xff08;Iterative Query&#xff09;域名的高速缓存 我们今天来看DNS域名系统 什么…

批量文件重命名技巧:轻松替换删除文件夹名中的字母,实现高效文件管理新境界

在数字化时代&#xff0c;我们每天都会面对大量的文件和文件夹。无论是工作文档、学习资料还是个人收藏&#xff0c;文件命名的规范性都显得尤为重要。然而&#xff0c;手动一个一个去修改文件名&#xff0c;不仅耗时耗力&#xff0c;还容易出错。那么&#xff0c;有没有一种方…

SAP ABAP 之面向对象OO

文章目录 前言一、类的理解二、如何创建ABAP类 a.类的定义与构成 b.类的访问区域 c.特殊方法 d.类的继承 三、类中参数的使用 a.IMPORTING / EXPORTING b.CHANGING c.RETURNING d.EX…

【Jmeter】插件详解:PerfMon Metrics Collector 服务器性能监控插件

目录 一、前言 二、PerfMon Metrics Collector 插件详解 (1)插件简介 (2)功能介绍 (3)应用场景 (4)使用指南 ① 环境准备 ② 服务端插件配置 ③ 监听器配置 ④ 图表设置 ⑤ 非 GUI 模式 三、ServerAgent 下载 四、ServerAgent 安装 (1)安装 (…

在python中指定pytorch训练时使用多块或某块GPU的方法

1. 引入 PyTorch是一个流行的深度学习框架&#xff0c;它提供了方便的API&#xff0c;使得在GPU上进行模型训练变得简单。 然而&#xff0c;有时我们可能需要指定使用多个GPU或者特定的GPU来进行训练&#xff0c;以满足不同的需求。 之所以在python中指定GPU&#xff0c;而不是…

水库枢纽乙级设计资质下的团队构建

1. 技术负责人与核心团队 技术负责人&#xff1a;需具备高级专业技术职称&#xff0c;且在水利枢纽设计领域有丰富的实践经验&#xff0c;能够指导解决复杂技术难题。核心设计团队&#xff1a;包括但不限于水工结构、水文水资源、地质勘察、电气自动化、环境保护等专业领域的工…

PHP杂货铺家庭在线记账理财管理系统源码

家庭在线记帐理财系统&#xff0c;让你对自己的开支了如指掌&#xff0c;图形化界面操作更简单&#xff0c;非常适合家庭理财、记账&#xff0c;系统界面简洁优美&#xff0c;操作直观简单&#xff0c;非常容易上手。 安装说明&#xff1a; 1、上传到网站根目录 2、用phpMyad…