在flask中返回requests响应
在flask服务端,有时候需要使用requests请求其他url,并将响应返回回去。查阅了flask文档,About Responses,可以直接构造响应结果进行返回。
If a tuple is returned the items in the tuple can provide extra information. Such tuples have to be in the form (response, status, headers) or (response, headers) where at least one item has to be in the tuple. The status value will override the status code and headers can be a list or dictionary of additional header values.
_headers = { 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'Accept-Encoding':'gzip, deflate, br', 'Accept-Language':'zh-CN,zh;q=0.8', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36' } def proxy(url, try_times=0): headers = dict(_headers) headers['Host'] = re.match(r'https?://([^/?]+)', url).group(1) response = requests.get(url, headers=headers, timeout=5, allow_redirects=False) #禁用自动跳转,因为跳转后Host可能会变,需要重新计算 if 300 < response.status_code < 400 and try_times < 3: url = response.headers.get('Location') if url.startswith('/'): return redirect(url, code=response.status_code) #相对地址,特殊处理 try_times += 1 return proxy(url, try_times) return response.content, response.status_code, response.headers.items()
这段代码在大部分情况下都运行良好。flask服务端显示相应正常,浏览器也看到有返回相应,偶尔浏览器出现ERR_CONTENT_DECODING_FAILED错误。看英文错误应该是,内容解码错误。
看了下requests的相应头中有,Content-Encoding: gzip,显示了网页内容进过gzip压缩。而requests会对部分压缩的内容进行解码:The gzip
and deflate
transfer-encodings are automatically decoded for you.
知道原因了,解决办法也很容易。1、删除相应头中的Content-Encoding,因为经过requests之后,返回给浏览器的已经不是压缩的内容了。2、重新计算Content-Length
def make_response(response): headers = dict(response.headers) content_encoding = headers.get('Content-Encoding') if content_encoding == 'gzip' or content_encoding == 'deflate': del headers['Content-Encoding'] if headers.get('Transfer-Encoding'): del headers['Transfer-Encoding'] if headers.get('Accept-Ranges'): del headers['Accept-Ranges'] headers['Content-Length'] = len(response.content) return response.content, response.status_code, headers.items()