文章目录

  • 背景
  • 遇到的问题:
      • 1、当通过response header 获取content-length 的时候,千牛的url 没有返回 content-length
      • 2、涉及到鉴权的私有文件url 获取不到真正的content-length
  • 一、解决获取不到content-length问题
      • 方法:通过python 的requests.head(url,headers)指定header 里的Accept-Encoding参数,来获取文件流真实的content-length
      • 原因:请求参数 headers里不指定文件流的Accept-Encoding,当服务器有对文件做了压缩后返回时,content-length就有可能获取不到
      • 实验对比:
      • 总结:
  • 二、解决获取不到真正的content-length问题
      • 思路1:服务器去掉鉴权的部分,通过requests.head 来直接获取真实的content-length
      • 思路2:通过curl 我们可以获取到文件的几个字节的方式来 间接获取这个文件流的字节大小
        • 方法和实验
  • 总结


背景

把同一份文件分别存放到了两个oss(可以理解为两个存储商),通过两个oss 返回的下载 url 获取 两个文件的content-length 和 content-type信息,对比是否一致

遇到的问题:

1、当通过response header 获取content-length 的时候,千牛的url 没有返回 content-length

2、涉及到鉴权的私有文件url 获取不到真正的content-length

通过curl -i url 是可以返回同一个文件 存在两个url 的content-length 的,那怎么通过python解决以上两个问题呢(方法不一定最好,欢迎拍砖!)

一、解决获取不到content-length问题

方法:通过python 的requests.head(url,headers)指定header 里的Accept-Encoding参数,来获取文件流真实的content-length

原因:请求参数 headers里不指定文件流的Accept-Encoding,当服务器有对文件做了压缩后返回时,content-length就有可能获取不到

参考了博文:https://blog.csdn/chouhuan1877/article/details/100808814 有说明获取不到content-length的原因

实验对比:

def head_getcontent(file,srcDownloadUrl,distDownloadUrl):
    session = requests.session()
    headers = {
        "Accept-Encoding": "identity"
    }
    # 通过requests.head()填入不同的参数处理千牛的文件url
    src_only_url = requests.head(url=srcDownloadUrl)
    src_url_headers = requests.head(url=srcDownloadUrl, headers=headers)
    src_url_headers_stream = requests.head(url=srcDownloadUrl, stream=True, headers=headers)

    print("src_only_url headers= {}".format(src_only_url.headers))
    print("src_url_headers headers= {}".format(src_url_headers.headers))
    print("src_url_headers_stream headers= {}".format(src_url_headers_stream.headers))
    print("src_only_url Content-Length= {}".format(src_only_url.headers['Content-Length']))
    print("src_url_headers Content-Length= {}".format(src_url_headers.headers['Content-Length']))
    print("src_url_headers_stream Content-Length= {}".format(src_url_headers_stream.headers['Content-Length']))

报错:

Traceback (most recent call last):
  File "F:/directory/Learn/request_url/head_get.py", line 76, in <module>
    print(head_getcontent(file,s,d))
  File "F:/directory/Learn/request_url/head_get.py", line 48, in head_getcontent
    print("src_only_url Content-Length= {}".format(src_only_url.headers['Content-Length']))
  File "D:\Anaconda3\lib\site-packages\requests\structures.py", line 52, in __getitem__
    return self._store[key.lower()][1]
KeyError: 'content-length'
Process finished with exit code 1

总结:

1)先了解一下Accept-Encoding:https://baike.baidu/item/Accept-Encoding/3239902?fr=aladdin,说明服务器对文件做压缩处理了,浏览器请求获取文件信息时需要header 指定Accept-Encoding,追加 headers 参数:“Accept-Encoding”: “identity” 后,就可以解决:KeyError: ‘content-length’ 的问题
2)python 的 requests.head(url,header) 可以获取到url 服务器返回的header信息(是不是所有的都能获取呢?这个就不一定了)

二、解决获取不到真正的content-length问题

问题:通过header 指定编码格式来获取带有鉴权信息的文件的content-length的时候,由于鉴权的存在,获取到的content-length 不是真实的 content-length

dis_url_headers = requests.head(url=distDownloadUrl, headers=headers)

结果:

说明:requests.head 获取不到具有鉴权信息的文件content-length(或者是需要什么参数来指定?欢迎指教~)

思路1:服务器去掉鉴权的部分,通过requests.head 来直接获取真实的content-length

这个是可行的,但是,很依赖去掉鉴权的操作,于是有了思路2

思路2:通过curl 我们可以获取到文件的几个字节的方式来 间接获取这个文件流的字节大小

HTTP1.1 协议(RFC2616)开始支持获取文件的部分内容。通过在 Header 里两个参数实现的,客户端发请求时对应的是 Range ,服务器端响应时对应的是 Content-Range。

方法和实验

那么通过python如何实现呢?
要在发出带 Range 的请求后,服务器才会在 Content-Range 头部返回当前接受的范围和文件总大小,那只能是发出一个 指定header里 range 参数的请求头的get 请求了

def head_getcontent(file,srcDownloadUrl,distDownloadUrl):
    headers = {
        "Accept-Encoding": "identity",
        "Range": "bytes=0-1"
    }
    # 处理千牛的url
    src_only_url = requests.head(url=srcDownloadUrl)
    src_url_headers = requests.head(url=srcDownloadUrl, headers=headers)
    src_url_headers_stream = requests.head(url=srcDownloadUrl, stream=True, headers=headers)

    print("src_only_url headers= {}".format(src_only_url.headers))
    print("src_url_headers headers= {}".format(src_url_headers.headers))
    print("src_url_headers_stream headers= {}".format(src_url_headers_stream.headers))
    # print("src_only_url Content-Length= {}".format(src_only_url.headers['Content-Length']))
    print("src_url_headers Content-Length= {}".format(src_url_headers.headers['Content-Length']))
    print("src_url_headers_stream Content-Length= {}".format(src_url_headers_stream.headers['Content-Length']))
    print("src_url_headers_stream Content-Range= {}".format(src_url_headers_stream.headers['Content-Range']))


    # 处理oss2 的url
    print("____________head_____________")
    dis_only_url = requests.head(url=distDownloadUrl)
    dis_url_headers = requests.head(url=distDownloadUrl, headers=headers)
    dis_url_headers_stream = requests.head(url=distDownloadUrl, stream=True, headers=headers)
    print("dis_only_url headers= {}".format(dis_only_url.headers))
    print("dis_url_headers headers= {}".format(dis_url_headers.headers))
    print("dis_url_headers_stream headers= {}".format(dis_url_headers_stream.headers))
    print("dis_only_url Content-Length= {}".format(dis_only_url.headers['Content-Length']))
    print("dis_url_headers Content-Length= {}".format(dis_url_headers.headers['Content-Length']))
    print("dis_url_headers_stream Content-Length= {}".format(dis_url_headers_stream.headers['Content-Length']))

    print("________session____get_____________")
    requests.DEFAULT_RETRIES = 5  # 增加重试连接次数
    session = requests.session()
    requests.keep_alive = False  # 关闭多余连接
    dis_only_geturl = session.get(url=distDownloadUrl)
    dis_geturl_headers = session.get(url=distDownloadUrl, headers=headers)
    dis_geturl_headers_stream = session.get(url=distDownloadUrl, stream=True, headers=headers)
    print("dis_only_geturl headers= {}".format(dis_only_geturl.headers))
    print("dis_geturl_headers headers= {}".format(dis_geturl_headers.headers))
    print("dis_geturl_headers_stream headers= {}".format(dis_geturl_headers_stream.headers))
    print("dis_only_geturl Content-Length= {}".format(dis_only_geturl.headers['Content-Length']))
    print("dis_geturl_headers Content-Length= {}".format(dis_geturl_headers.headers['Content-Length']))
    print("dis_geturl_headers_stream Content-Length= {}".format(dis_geturl_headers_stream.headers['Content-Length']))
    print("dis_geturl_headers_stream Content-Range= {}".format(dis_geturl_headers_stream.headers['Content-Range']))

返回:

总结

既要获取到 oss1 的content-length 也要获取到 oss2 带有鉴权的url静态资源信息 只能通过get 指定header 的range 让服务器返回 content-range 来对比了

如果需要转载请注明出处
如果有说的不对的地方或 有更好的实现方式,欢迎拍砖🧐 和 赐教😊

更多推荐

通过python request库获取文件大小和文件类型(解决报错:KeyError: ‘content-length‘)