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

2024-06-13 09:04

本文主要是介绍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 //手动断网导致访问失败

这篇关于19.2 HTTP客户端-定制HTTP请求、调试HTTP、响应超时的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1056860

相关文章

ASIO网络调试助手之一:简介

多年前,写过几篇《Boost.Asio C++网络编程》的学习文章,一直没机会实践。最近项目中用到了Asio,于是抽空写了个网络调试助手。 开发环境: Win10 Qt5.12.6 + Asio(standalone) + spdlog 支持协议: UDP + TCP Client + TCP Server 独立的Asio(http://www.think-async.com)只包含了头文件,不依

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

【Linux】应用层http协议

一、HTTP协议 1.1 简要介绍一下HTTP        我们在网络的应用层中可以自己定义协议,但是,已经有大佬定义了一些现成的,非常好用的应用层协议,供我们直接使用,HTTP(超文本传输协议)就是其中之一。        在互联网世界中,HTTP(超文本传输协议)是一个至关重要的协议,他定义了客户端(如浏览器)与服务器之间如何进行通信,以交换或者传输超文本(比如HTML文档)。

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念

vscode中文乱码问题,注释,终端,调试乱码一劳永逸版

忘记咋回事突然出现了乱码问题,很多方法都试了,注释乱码解决了,终端又乱码,调试窗口也乱码,最后经过本人不懈努力,终于全部解决了,现在分享给大家我的方法。 乱码的原因是各个地方用的编码格式不统一,所以把他们设成统一的utf8. 1.电脑的编码格式 开始-设置-时间和语言-语言和区域 管理语言设置-更改系统区域设置-勾选Bata版:使用utf8-确定-然后按指示重启 2.vscode

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而

Java Websocket实例【服务端与客户端实现全双工通讯】

Java Websocket实例【服务端与客户端实现全双工通讯】 现很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏 览器需要不断的向服务器发出请求,然而HTTP