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://dappradar.com/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-uri.cloudflare.com/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重定向

相关文章
|
人工智能 安全 Shell
Go并发编程避坑指南:从数据竞争到同步原语的解决方案
在高并发场景下,如钱包转账,数据一致性至关重要。本文通过实例演示了 Go 中如何利用 `sync.Mutex` 和 `sync.RWMutex` 解决数据竞争问题,帮助开发者掌握并发编程中的关键技能。
Go并发编程避坑指南:从数据竞争到同步原语的解决方案
|
JSON 中间件 Go
Go 网络编程:HTTP服务与客户端开发
Go 语言的 `net/http` 包功能强大,可快速构建高并发 HTTP 服务。本文从创建简单 HTTP 服务入手,逐步讲解请求与响应对象、URL 参数处理、自定义路由、JSON 接口、静态文件服务、中间件编写及 HTTPS 配置等内容。通过示例代码展示如何使用 `http.HandleFunc`、`http.ServeMux`、`http.Client` 等工具实现常见功能,帮助开发者掌握构建高效 Web 应用的核心技能。
634 61
|
12月前
|
存储 监控 算法
企业电脑监控系统中基于 Go 语言的跳表结构设备数据索引算法研究
本文介绍基于Go语言的跳表算法在企业电脑监控系统中的应用,通过多层索引结构将数据查询、插入、删除操作优化至O(log n),显著提升海量设备数据管理效率,解决传统链表查询延迟问题,实现高效设备状态定位与异常筛选。
259 3
Go语言同步原语与数据竞争:Mutex 与 RWMutex
在Go语言并发编程中,数据竞争是多个goroutine同时读写共享变量且未加控制导致的问题,可能引发程序崩溃或非确定性错误。为解决此问题,Go提供了`sync.Mutex`和`sync.RWMutex`两种同步机制。`Mutex`用于保护临界区,确保同一时间只有一个goroutine访问;`RWMutex`支持多读单写的细粒度控制,适合读多写少场景。使用时需避免死锁,并借助`-race`工具检测潜在的数据竞争,从而提升程序稳定性和性能。
365 51
|
存储 C++
UE5 C++:自定义Http节点获取Header数据
综上,通过为UE5创建一个自定义HTTP请求类并覆盖GetResult方法,就能成功地从HTTP响应的Header数据中提取信息。在项目中使用自定义类,不仅可以方便地访问响应头数据,也可随时使用这些信息。希望这种方法可以为你的开发过程带来便利和效益。
598 35
|
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。
|
编译器 测试技术 Go
Go语言同步原语与数据竞争:数据竞争的检测工具
本文介绍了 Go 语言中数据竞争(Data Race)的概念及其检测方法。数据竞争发生在多个 Goroutine 无同步访问共享变量且至少一个为写操作时,可能导致程序行为不稳定或偶发崩溃。Go 提供了内置的竞态检测器(Race Detector),通过 `-race` 参数可轻松检测潜在问题。文章还展示了如何使用锁或原子操作修复数据竞争,并总结了在开发和 CI 流程中启用 `-race` 的最佳实践,以提升程序稳定性和可靠性。
Go语言同步原语与数据竞争:WaitGroup
本文介绍了 Go 语言中 `sync.WaitGroup` 的使用方法和注意事项。作为同步原语,它通过计数器机制帮助等待多个 goroutine 完成任务。核心方法包括 `Add()`(设置等待数量)、`Done()`(减少计数)和 `Wait()`(阻塞直到计数归零)。文章详细讲解了其基本原理、典型用法(如等待 10 个 goroutine 执行完毕),并提供了代码示例。同时指出常见错误,例如 `Add()` 必须在 goroutine 启动前调用,以及 WaitGroup 不可重复使用。最后总结了适用场景和使用要点,强调避免竞态条件与变量捕获陷阱。
|
网络架构
CondaHTTPError HTTP 000 CONNECTION FAILED错误解决方案
以上就是解决"CondaHTTPError: HTTP 000 CONNECTION FAILED"错误的一些方法。希望这些方法能够帮助你解决问题。如果以上方法都无法解决你的问题,你可能需要寻求专业的技术支持。
2105 23
|
安全 Go 调度
Go同步原语与数据竞争:原子操作(atomic)
本文介绍了Go语言中`sync/atomic`包的使用,帮助避免多goroutine并发操作时的数据竞争问题。原子操作是一种不可中断的操作,确保变量读写的安全性。文章详细说明了常用函数如`Load`、`Store`、`Add`和`CompareAndSwap`的功能与应用场景,并通过并发计数器示例展示了其实现方式。此外,对比了原子操作与锁的优缺点,强调原子操作适用于简单变量的高效同步,而不适合复杂数据结构。最后提醒开发者注意使用场景限制,合理选择同步工具以优化性能。

热门文章

最新文章