首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Python2.7将bz2压缩数据发送为utf-8字符串。

使用Python2.7将bz2压缩数据发送为utf-8字符串。
EN

Stack Overflow用户
提问于 2015-05-15 05:43:07
回答 2查看 1.6K关注 0票数 1

我试图使用gunicorn发送一个utf-8编码的字符串,这是一个bz2压缩的结果,作为对get请求的响应。

这是我在gunicorn服务器端的代码:

代码语言:javascript
复制
def app(environ, start_response):
    data = "Hello, World!" * 10
    compressed_data = bz2.compress(data)
    start_response("200 OK", [("Content-Type", "text/plain"),
                              ('charset', 'utf-8'),
                              ("Content-Length", str(len(compressed_data))),
                              ('Access-Control-Allow-Headers', '*'),
                              ('Access-Control-Allow-Origin', '*'),
                              # ('Content-Transfer-Encoding', 'BASE64'),
                          ])
    return iter([compressed_data])

当我尝试使用Python请求包从客户端获取请求时,如下所示

代码语言:javascript
复制
import bz2
import requests
res = requests.get('http://127.0.0.1:8000')
bz2.decompress(res.text)

它带来了一个例外

代码语言:javascript
复制
UnicodeEncodeError: 'ascii' codec can't encode character u'\xab' in position 11: ordinal not in range(128)

表示当试图打印响应文本时不能解码响应

代码语言:javascript
复制
print(res.text)
>>u'BZh91AY&SYy\xabm\x99\x00\x00\x13\x97\x80`\x04\x00@\x00\x80\x06\x04\x90\x00 \x00\xa5P\xd0\xda\x10\x03\x0e\xd3\xd4\xdai4\x9bO\x93\x13\x13\xc2b~\x9c\x17rE8P\x90y\xabm\x99'

打印编码文本时

代码语言:javascript
复制
import bz2
print(bz2.compress("Hello, World!" * 10))
>> 'BZh91AY&SYy\xabm\x99\x00\x00\x13\x97\x80`\x04\x00@\x00\x80\x06\x04\x90\x00 \x00\xa5P\xd0\xda\x10\x03\x0e\xd3\xd4\xdai4\x9bO\x93\x13\x13\xc2b~\x9c\x17rE8P\x90y\xabm\x99'

唯一的区别是unicode符号,我通过调整客户端的数据来解决这个问题,以使响应字符串可解码,但我想知道如何在服务器端解决这个问题?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-05-17 18:57:08

您不能以utf-8的形式发送bzip2压缩数据。它是二进制数据,不是文本。

如果您的http客户端接受bzip2内容编码(不标准),则可以发送使用bzip2压缩的utf-8编码文本:

代码语言:javascript
复制
#!/usr/bin/env python
import bz2

def app(environ, start_response):
    status = '200 OK'
    headers = [('Content-type', 'text/plain; charset=utf-8')]
    data = (u'Hello \N{SNOWMAN}\n' * 10).encode('utf-8')

    if 'bzip2' in environ.get('HTTP_ACCEPT_ENCODING', ''): # use bzip2 only if requested
        data = bz2.compress(data)
        headers.append(('Content-Encoding', 'bzip2'))

    headers.append(('Content-Length', str(len(data))))
    start_response(status, headers)
    return data

示例

未压缩响应:

代码语言:javascript
复制
$ http -v 127.0.0.1:8000
GET / HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: 127.0.0.1:8000
User-Agent: HTTPie/0.9.2



HTTP/1.1 200 OK
Connection: close
Content-Length: 100
Content-type: text/plain; charset=utf-8
Date: Sun, 17 May 2015 18:47:50 GMT
Server: gunicorn/19.3.0

Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃

如果客户端指定接受bzip2,则为bzip2压缩响应:

代码语言:javascript
复制
$ http -v 127.0.0.1:8000 Accept-Encoding:bzip2 
GET / HTTP/1.1
Accept: */*
Accept-Encoding: bzip2
Connection: keep-alive
Host: 127.0.0.1:8000
User-Agent: HTTPie/0.9.2



HTTP/1.1 200 OK
Connection: close
Content-Encoding: bzip2
Content-Length: 65
Content-type: text/plain; charset=utf-8
Date: Sun, 17 May 2015 18:48:23 GMT
Server: gunicorn/19.3.0



+-----------------------------------------+
| NOTE: binary data not shown in terminal |
+-----------------------------------------+

下面是使用requests库的相应http客户机:

代码语言:javascript
复制
#!/usr/bin/env python
from __future__ import print_function
import bz2
import requests # $ pip install requests

r = requests.get('http://localhost:8000', headers={'Accept-Encoding': 'gzip, deflate, bzip2'})
content = r.content
print(len(content))
if r.headers['Content-Encoding'].endswith('bzip2'): # requests doesn't understand bzip2
    content = bz2.decompress(content)
print(len(content))
text = content.decode(r.encoding)
print(len(text))
print(text, end='')

输出

代码语言:javascript
复制
65
100
80
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃

否则(没有非标准的接受编码),您应该将数据以application/octet-stream的形式以@icedtree建议的形式发送。

代码语言:javascript
复制
#!/usr/bin/env python
import bz2

def app(environ, start_response):
    status = '200 OK'
    headers = [('Content-type', 'application/octet-stream')]
    data = bz2.compress((u'Hello \N{SNOWMAN}\n' * 10).encode('utf-8'))

    headers.append(('Content-Length', str(len(data))))
    start_response(status, headers)
    return data

示例

代码语言:javascript
复制
$ http 127.0.0.1:8000 
HTTP/1.1 200 OK
Connection: close
Content-Length: 65
Content-type: application/octet-stream
Date: Sun, 17 May 2015 18:53:55 GMT
Server: gunicorn/19.3.0



+-----------------------------------------+
| NOTE: binary data not shown in terminal |
+-----------------------------------------+

bzcat接受bzip2内容:

代码语言:javascript
复制
$ http 127.0.0.1:8000 | bzcat
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃
Hello ☃

由于终端使用utf-8编码,所以数据被正确显示.

票数 2
EN

Stack Overflow用户

发布于 2015-05-15 07:29:42

问题是字符串以unicode的形式出现。您不应该试图将bz2压缩数据解释为文本。

关于如何将数据解释为原始数据而不是文本,请参见请求文档

代码语言:javascript
复制
res.content  # not res.text

此外,数据不应首先以text/plain的形式发送。BZ2压缩数据不是文本,应该以application/octet-stream (即字节流)的形式发送。

快速破解将文本重新解释为字节流(因为默认的ascii编解码器不会处理超出0-127范围的字节,所以我们使用ISO-8859-1对数据进行编码。

代码语言:javascript
复制
>>> text = u'BZh91AY&SYy\xabm\x99\x00\x00\x13\x97\x80`\x04\x00@\x00\x80\x06\x04\x90\x00 \x00 \xa5P\xd0\xda\x10\x03\x0e\xd3\xd4\xdai4\x9bO\x93\x13\x13\xc2b~\x9c\x17rE8P\x90y\xabm\x99'
>>> byte_string = text.encode('ISO-8859-1')
>>> byte_string
'BZh91AY&SYy\xabm\x99\x00\x00\x13\x97\x80`\x04\x00@\x00\x80\x06\x04\x90\x00 \x00 \xa5P\xd0\xda\x10\x03\x0e\xd3\xd4\xdai4\x9bO\x93\x13\x13\xc2b~\x9c\x17rE8P\x90y\xabm\x99'
>>> bz2.decompress(byte_string)
'Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!'

但理想情况下,您应该修复您的数据类型。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30252301

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档