Go重写http请求重定向的方法

 更新时间:2024年08月30日 11:28:08   作者:二郎腿  
当使用Go语言进行 HTTP 请求时,默认情况下,http.Client 会自动处理服务器返回的重定向响应(3xx 状态码),本文将详细介绍如何在 Go 中实现禁止 HTTP 请求的重定向、限制重定向次数以及添加自定义重定向策略,需要的朋友可以参考下

一、背景

当使用 Go 语言进行 HTTP 请求时,默认情况下,http.Client 会自动处理服务器返回的重定向响应(3xx 状态码)。但有时候,我们可能需要在请求中禁止自动的重定向。本文将详细介绍如何在 Go 中实现禁止 HTTP 请求的重定向、限制重定向次数以及添加自定义重定向策略

二、默认值

http.ClientCheckRedirect 字段是用于处理重定向策略的函数,如果 CheckRedirect 不是 nil,则客户端会在遵循 HTTP 重定向之前调用它。参数 req 和 via 是即将到来的请求和已经发出的请求,最早发出的请求在前面。如果 CheckRedirect 返回错误,则 ClientGet 方法将返回前一个 Response(其 Body 关闭)和 CheckRedirect 的错误(包装在 url.Error),而不是继续发出重定向请求。作为一种特殊情况,如果 CheckRedirect 返回 ErrUseLastResponse,则返回的最新响应体的 body, 且 body 未关闭,并返回 nil 错误。如果 CheckRedirectnil,则客户端使用其默认重定向策略,即在连续 10 个请求后停止。相关源码如下,来自src/net/http/client.go

func defaultCheckRedirect(req *Request, via []*Request) error {
	if len(via) >= 10 {
		return errors.New("stopped after 10 redirects")
	}
	return nil
}

三、禁止重定向

通过设置 http.ClientCheckRedirect 字段为一个为一个自定义的函数,可以控制重定向的行为。这个函数接收一个 *http.Request 和一个 []*http.Request 参数,前者代表当前正在处理的请求,后者代表已经请求的重定向请求链,返回 http.ErrUseLastResponse 错误,收到这个错误后,http.Client 不会再继续重定向请求,并且返回一个 nil 错误给上游,如下:

func forbidRedirect(req *http.Request, via []*http.Request) (err error) {
	// 返回一个错误,表示不允许重定向
	return http.ErrUseLastResponse
}

如果 CheckRedirect 字段不设置值,或是设置 nil 值,都会采用上述的默认函数defaultCheckRedirect,进行最多 10 重定向;如果返回的不是 http.ErrUseLastResponse 错误,那么该请求将会收到一个非 nil 的错误。

四、更改重定向次数

即更改对 []*http.Request 参数长度的限制即可,一定不能返回 http.ErrUseLastResponse 错误。

func limitRedirect(req *http.Request, via []*http.Request) error {
	// via 记录了已经请求的 url 个数
	if len(via) >= 3 {
		return errors.New("stopped after max redirects")
	}
	return nil
}

五、自定义重定向策略

通过对重定向函数的重写,添加一些自定义的逻辑,并将该函数其赋值给 http client 的CheckRedirect,可以实现自定义重定向策略,其中 req.Response 参数表示导致该次重定向的返回。

func myRedirect(req *http.Request, via []*http.Request) error {
	// 限制重定向次数
	if len(via) >= 10 {
		return errors.New("stopped after 10 redirects")
	}
	if req == nil || req.URL == nil || req.Response == nil || !strings.HasPrefix(req.Response.Status, "3") {
		return http.ErrUseLastResponse
	}
	// 禁止重定向下载 apk 文件
	if strings.HasSuffix(req.URL.Path, "apk") {
		return fmt.Errorf("invalid redirect url, path: %s", req.URL.Path)
	}

	// 限制重定向请求类型
	contentType := req.Response.Header.Get("Content-Type")
	if strings.Contains(contentType, "octet-stream") {
		return fmt.Errorf("invalid redirect url, type: %s", contentType)
	}

	// 限制重定向请求体长度
	contentLength := req.Response.Header.Get("Content-Length")
	if contentLength != "" {
		length, _ := strconv.Atoi(contentLength)
		if length > 1000 {
			return fmt.Errorf("invalid redirect url, len: %s", contentLength)
		}
	}

	// 限制重定向请求传输编码
	transferEncoding := req.Response.Header.Get("Transfer-Encoding")
	if strings.Contains(transferEncoding, "chunked") {
		return fmt.Errorf("invalid redirect url, encoding: %s", transferEncoding)
	}

	return http.ErrUseLastResponse
}

六、完整示例

package main

import (
	"errors"
	"fmt"
	"io"
	"net/http"
)

func forbidRedirect(req *http.Request, via []*http.Request) (err error) {
	// 返回一个错误,表示不允许重定向
	return http.ErrUseLastResponse
}

func limitRedirect(req *http.Request, via []*http.Request) error {
	// via 记录了已经请求的 url 个数
	if len(via) >= 3 {
		return errors.New("stopped after max redirects")
	}
	return nil
}
func main() {
    // 创建一个自定义的 HTTP Client
    client := &http.Client{
        CheckRedirect: forbidRedirect,
    }

    // 创建一个 GET 请求,该 url 一定要重定向
    req, err := http.NewRequest("GET", "https://weibo.com", nil)
    if err != nil {
        fmt.Println("Error creating request:", err)
        return
    }

    // 使用自定义的 Client 发送请求
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error sending request:", err)
        return
    }
    defer resp.Body.Close()

    fmt.Println("Response Status:", resp.Status)

	body, _ := io.ReadAll(resp.Body)
	fmt.Println("Response Body:", string(body))
}

七、总结

http.Client 的 CheckRedirect 字段是用于处理重定向策略的函数,如果不赋值时就会采用默认函数,默认最多重定向 10 次。我们可以通过重写默认函数来禁止重定向、改变重定向次数以及添加自定义的重定向过滤逻辑。

到此这篇关于Go重写http请求重定向的方法的文章就介绍到这了,更多相关Go http请求重定向内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • golang 墙上时钟与单调时钟的实现

    golang 墙上时钟与单调时钟的实现

    本文主要介绍了golang 墙上时钟与单调时钟的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • Golang中堆排序的实现

    Golang中堆排序的实现

    堆是一棵基于数组实现的特殊的完全二叉树,本文主要介绍了Golang中堆排序的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • Golang如何将日志以Json格式输出到Kafka

    Golang如何将日志以Json格式输出到Kafka

    这篇文章主要介绍了Golang将日志以Json格式输出到Kafka的方法,这篇文章还会提供一种输出Json格式日志的方法,本文结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • go浮点数转字符串保留小数点后N位的完美解决方法

    go浮点数转字符串保留小数点后N位的完美解决方法

    这篇文章主要介绍了go浮点数转字符串保留小数点后N位解决办法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-05-05
  • 解读rand.Seed(time.Now().UnixNano())的作用及说明

    解读rand.Seed(time.Now().UnixNano())的作用及说明

    这篇文章主要介绍了关于rand.Seed(time.Now().UnixNano())的作用及说明,具有很好的参考价值,希望对大家有所帮助。
    2023-03-03
  • Go 语言前缀树实现敏感词检测

    Go 语言前缀树实现敏感词检测

    这篇文章主要为大家介绍了Go语言前缀树实现敏感词检测实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • golang中拿slice当queue和拿list当queue使用分析

    golang中拿slice当queue和拿list当queue使用分析

    这篇文章主要为大家介绍了golang 中拿slice当queue和拿list当queue使用分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • go实现thrift的网络传输性能及需要注意问题示例解析

    go实现thrift的网络传输性能及需要注意问题示例解析

    这篇文章主要为大家介绍了go实现thrift的网络传输性能及需要注意问题示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Go语言Web编程实现Get和Post请求发送与解析的方法详解

    Go语言Web编程实现Get和Post请求发送与解析的方法详解

    这篇文章主要介绍了Go语言Web编程实现Get和Post请求发送与解析的方法,结合实例形式分析了Go语言客户端、服务器端结合实现web数据get、post发送与接收数据的相关操作技巧,需要的朋友可以参考下
    2017-06-06
  • golang判断字符串是是否包含另一字符串的示例代码

    golang判断字符串是是否包含另一字符串的示例代码

    在Go语言中,可以使用strings.Contains()函数来判断一个字符串是否包含另一个字符串,该函数接受两个参数:要搜索的字符串和要查找的子字符串,如果子字符串存在于要搜索的字符串中,则返回true,否则返回false,下面通过示例详细介绍,感兴趣的朋友一起看看吧
    2023-09-09

最新评论