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重定向

相关文章
|
18天前
|
JSON 安全 前端开发
类型安全的 Go HTTP 请求
类型安全的 Go HTTP 请求
|
1月前
|
程序员 Go 网络架构
不看就落后了,Go 1.22 中更好的http router
不看就落后了,Go 1.22 中更好的http router
|
16天前
|
缓存 Go
Go引用包版本更新但是被引用的包的子包并没有出现在vendor中的问题和解决方案
文章讨论了在Go模块项目中升级依赖包版本时遇到的子包未出现在vendor目录的问题,并提供了直接删除旧版本引用并重新执行`go mod vendor`的解决方案。
21 0
|
16天前
|
IDE Go 开发工具
Go Error module declares its path as but was required as解决方案
文章提供了一个解决方案,用于处理在Go工程中将依赖的仓库从A更换为B(即使它们完全相同)时遇到的路径声明错误,建议通过发布新版本来解决此问题。
36 0
|
1月前
|
JSON 测试技术 Go
Go Kit中读取原始HTTP请求体的方法
Go Kit中读取原始HTTP请求体的方法
|
1月前
|
网络协议 Go
go的net/http有哪些值得关注的细节?
go的net/http有哪些值得关注的细节?
|
1月前
|
网络协议 Go
【go笔记】简单的http服务
【go笔记】简单的http服务
|
2月前
|
Go
Go 项目自动重载解决方案 —— Air 使用入门
**Air**: 提升Go开发效率的利器!自动重载工具,监听文件变化,实时编译运行,无需频繁重启。安装:启用Go Module后,运行`GO111MODULE=on go install github.com/cosmtrek/air@latest`。启动项目:`air`,配置文件默认为`air.toml`。集成到项目,忽略`tmp/`目录。让代码更改即时生效,专注编码,告别手动重启。适用于开发环境,生产环境禁用。[更多详情](https://github.com/cosmtrek/air)
52 1
|
2月前
|
JSON Java Serverless
函数计算产品使用问题之如何使用Go SDK从HTTP上下文中提取JSON数据
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
2月前
|
Go
Go中 net/http 使用
Go中 net/http 使用
14 0