Angular6 HttpClient POST 和 flask - httpclient 和 curl 请求之间后端的内容差异
Angular6 HttpClient POST and flask - content difference on backend between httpclient and curl request
我正在使用 HttpClient 做一个 post:
return this.http.post(`reporting/report/generate/${code}`, {'mimetype': mimetype, 'input': value}, {responseType: mimetype});
针对我的 API 服务器使用以下 mimetype:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
,所以我正在获取 xlsx 数据。
在服务器端(通过 nginx 和 uwsgi),我 运行 flask 具有以下代码(裁剪):
outputStream = io.BytesIO()
workbook = xlsxwriter.Workbook(outputStream)
worksheet = workbook.add_worksheet(Report.name())
[...]
worksheet.write(0, 0, 'YY', 'XX')
workbook.close()
output = outputStream.getvalue()
outputStream.close()
return Response(output, mimetype=mimetype)
(我的回复使用相同的 mimetype)。
回到 angular,我正在使用 blob url 等来下载我的文件,但这并不重要。
问题是当我从 angular 发出 Http 请求时,我的 Excel 文件被破坏了,当我使用 curl 执行完全相同的请求(从 Chrome 网络选项卡)。
但是:我在服务器端写了一个临时 xlsx 文件,两个文件都可以。
我打印了 output
的字节,我看到有些字节是不同的:
b'PK\x03\x04\x14\x00\x00\x00\x08\x00\x13}\x15M\xf5\x8e\x0eH\xb9\x01\x00\x00I\x04\x00\x00\x18\...docProps/app.xmlPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\x13}\x15M\x9c\xed\xd2_%\x01\x00\x00P\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00
对比
b'PK\x03\x04\x14\x00\x00\x00\x08\x003}\x15M\xf5\x8e\x0eH\xb9\x01\x00\x00I\x04\x00\x00\...docProps/app.xmlPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x003}\x15M\xa5\xc4\xa4$%\x01\x00\x00P\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x81E\x06\x00\x00docProps/core.xmlPK\x01\x02\x14\x03\
90%的字节是相同的,但有些是不同的。
我找了好几个小时都没找到问题所在。
奇怪的是,临时文件在这两种情况下都可以,但表示显示略有不同。
我也分析了 Requests,我发现了一个小区别:
<Request 'http://lsdev01/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1' [POST]>
{'environ': {'QUERY_STRING': ''
REQUEST_METHOD': 'POST'
CONTENT_TYPE': 'application/json'
CONTENT_LENGTH': '126'
REQUEST_URI': '/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1'
PATH_INFO': '/report/generate/DEMO_TECH_DEMO1'
DOCUMENT_ROOT': '/usr/share/nginx/html'
SERVER_PROTOCOL': 'HTTP/1.1'
REQUEST_SCHEME': 'http'
REMOTE_ADDR': '192.168.69.16'
REMOTE_PORT': '54436'
SERVER_PORT': '80'
SERVER_NAME': 'lsdev01'
HTTP_HOST': 'lsdev01'
HTTP_CONNECTION': 'keep-alive'
HTTP_CONTENT_LENGTH': '126'
HTTP_PRAGMA': 'no-cache'
HTTP_CACHE_CONTROL': 'no-cache'
HTTP_ACCEPT': 'application/json, text/plain, */*'
HTTP_ORIGIN': 'http://localhost:4213'
HTTP_AUTHORIZATION': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MzQ0OTM4MDksInN1YiI6eyIkJFVTUklETE9HSU4iOiIxNDQ5IiwiJCRVU1JOQU1FTE9HSU4iOiI5OSAtIHdlaXRlcmUgRmFjaGdydXBwZW4iLCIkJFVTUkNPREVMT0dJTiI6IkRXRSIsIiQkU0VTU0lPTkxPR0lEIjoxLCIkJFNJVEVJRCI6IjkwMDAwMDMyNzAiLCIkJFNJVEVHUlAiOiJMQUJPIiwiJCRURVNURkVBVFVSRUxJU1QiOiJURVNUUkVGTkVXXHUwMDFiTVVMVElERUJcdTAwMWJSRVRSSUVWRU5FV1x1MDAxYlJFU1JFRlx1MDAxYkxYUkJBQzJcdTAwMWJGQ1RURVNUXHUwMDFiQ09NVEVTVFx1MDAxYk5PTkVVTklRVUVCQ1x1MDAxYlBFUkZfTFhURVhUIiwiJCRMQU5HVUFHRSI6IiIsIkxBTkdVQUdFIjpudWxsfSwiZXhwIjoxNTM0NTgwMjA5LCJpbnN0YW5jZSI6ImRldiJ9.33Pid_GDPP6LUgoGzv_uU26QisBJNqoqsc7uTczdLvU'
HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
HTTP_CONTENT_TYPE': 'application/json'
HTTP_REFERER': 'http://localhost:4213/login'
HTTP_ACCEPT_ENCODING': 'gzip, deflate'
HTTP_ACCEPT_LANGUAGE': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7,fr;q=0.6'
SCRIPT_NAME': '/lx/ui_api/dev/dwe/dwe/reporting'
wsgi.input': <uwsgi._Input object at 0x7fd792236300>
wsgi.version': (1, 0)
wsgi.errors': <_io.TextIOWrapper name=2 mode='w' encoding='UTF-8'>
wsgi.run_once': False
wsgi.multithread': True
wsgi.multiprocess': False
wsgi.url_scheme': 'http'
uwsgi.version': b'2.0.15'
uwsgi.core': 3
uwsgi.node': b'lsdev01'
werkzeug.request': <Request 'http://lsdev01/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1' [POST]>}
shallow': False
view_args': {'reportCode': 'DEMO_TECH_DEMO1'}
url_rule': <Rule '/report/generate/<reportCode>' (OPTIONS, POST) -> report_generate>
_parsed_content_type': ('application/json', {})
stream': <werkzeug.wsgi.LimitedStream object at 0x7fd78f7d7438>
_cached_data': b'{"mimetype":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","input":{"header":"Test 1","footer":"Test 2"}}'
_cached_json': {'mimetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
input': {'header': 'Test 1'
footer': 'Test 2'}}
url': 'http://lsdev01/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1'}
对比
<Request 'http://lsdev01/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1' [POST]>
{'environ': {'QUERY_STRING': ''
REQUEST_METHOD': 'POST'
CONTENT_TYPE': 'application/json'
CONTENT_LENGTH': '126'
REQUEST_URI': '/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1'
PATH_INFO': '/report/generate/DEMO_TECH_DEMO1'
DOCUMENT_ROOT': '/usr/share/nginx/html'
SERVER_PROTOCOL': 'HTTP/1.1'
REQUEST_SCHEME': 'http'
REMOTE_ADDR': '192.168.69.18'
REMOTE_PORT': '55154'
SERVER_PORT': '80'
SERVER_NAME': 'lsdev01'
HTTP_HOST': 'lsdev01'
HTTP_ACCEPT_ENCODING': 'deflate, gzip'
HTTP_ACCEPT': 'application/json, text/plain, */*'
HTTP_REFERER': 'http://localhost:4213/login'
HTTP_ORIGIN': 'http://localhost:4213'
HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
HTTP_AUTHORIZATION': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MzQ0OTM4MDksInN1YiI6eyIkJFVTUklETE9HSU4iOiIxNDQ5IiwiJCRVU1JOQU1FTE9HSU4iOiI5OSAtIHdlaXRlcmUgRmFjaGdydXBwZW4iLCIkJFVTUkNPREVMT0dJTiI6IkRXRSIsIiQkU0VTU0lPTkxPR0lEIjoxLCIkJFNJVEVJRCI6IjkwMDAwMDMyNzAiLCIkJFNJVEVHUlAiOiJMQUJPIiwiJCRURVNURkVBVFVSRUxJU1QiOiJURVNUUkVGTkVXXHUwMDFiTVVMVElERUJcdTAwMWJSRVRSSUVWRU5FV1x1MDAxYlJFU1JFRlx1MDAxYkxYUkJBQzJcdTAwMWJGQ1RURVNUXHUwMDFiQ09NVEVTVFx1MDAxYk5PTkVVTklRVUVCQ1x1MDAxYlBFUkZfTFhURVhUIiwiJCRMQU5HVUFHRSI6IiIsIkxBTkdVQUdFIjpudWxsfSwiZXhwIjoxNTM0NTgwMjA5LCJpbnN0YW5jZSI6ImRldiJ9.33Pid_GDPP6LUgoGzv_uU26QisBJNqoqsc7uTczdLvU'
HTTP_CONTENT_TYPE': 'application/json'
HTTP_CONTENT_LENGTH': '126'
SCRIPT_NAME': '/lx/ui_api/dev/dwe/dwe/reporting'
wsgi.input': <uwsgi._Input object at 0x7fd792236300>
wsgi.version': (1, 0)
wsgi.errors': <_io.TextIOWrapper name=2 mode='w' encoding='UTF-8'>
wsgi.run_once': False
wsgi.multithread': True
wsgi.multiprocess': False
wsgi.url_scheme': 'http'
uwsgi.version': b'2.0.15'
uwsgi.core': 0
uwsgi.node': b'lsdev01'
werkzeug.request': <Request 'http://lsdev01/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1' [POST]>}
shallow': False
view_args': {'reportCode': 'DEMO_TECH_DEMO1'}
url_rule': <Rule '/report/generate/<reportCode>' (OPTIONS, POST) -> report_generate>
_parsed_content_type': ('application/json', {})
stream': <werkzeug.wsgi.LimitedStream object at 0x7fd78f7bcf98>
_cached_data': b'{"mimetype":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","input":{"header":"Test 1","footer":"Test 2"}}'
_cached_json': {'mimetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
input': {'header': 'Test 1'
footer': 'Test 2'}}
url': 'http://lsdev01/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1'}
不过没什么特别的...
有人知道问题出在哪里吗?
编辑:我也试过 send_files,但我遇到了同样的问题。
该死的!我知道了!
我在服务器端编码为 base64:
return Response(base64.b64encode(output), mimetype=mimetype)
在 angular 中,我结合了一些在 so 上找到的函数:
download(mimetype, data) {
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
var blob = new Blob([s2ab(atob(data))], {type: mimetype});
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
}
atob = 解码base64编码的字符串
s2ab = 字符串到 blob 的数组缓冲区
我认为这一切的根源是客户端和服务器之间的编码问题。但是我没有解释为什么!
我正在使用 HttpClient 做一个 post:
return this.http.post(`reporting/report/generate/${code}`, {'mimetype': mimetype, 'input': value}, {responseType: mimetype});
针对我的 API 服务器使用以下 mimetype:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
,所以我正在获取 xlsx 数据。
在服务器端(通过 nginx 和 uwsgi),我 运行 flask 具有以下代码(裁剪):
outputStream = io.BytesIO()
workbook = xlsxwriter.Workbook(outputStream)
worksheet = workbook.add_worksheet(Report.name())
[...]
worksheet.write(0, 0, 'YY', 'XX')
workbook.close()
output = outputStream.getvalue()
outputStream.close()
return Response(output, mimetype=mimetype)
(我的回复使用相同的 mimetype)。
回到 angular,我正在使用 blob url 等来下载我的文件,但这并不重要。 问题是当我从 angular 发出 Http 请求时,我的 Excel 文件被破坏了,当我使用 curl 执行完全相同的请求(从 Chrome 网络选项卡)。
但是:我在服务器端写了一个临时 xlsx 文件,两个文件都可以。
我打印了 output
的字节,我看到有些字节是不同的:
b'PK\x03\x04\x14\x00\x00\x00\x08\x00\x13}\x15M\xf5\x8e\x0eH\xb9\x01\x00\x00I\x04\x00\x00\x18\...docProps/app.xmlPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\x13}\x15M\x9c\xed\xd2_%\x01\x00\x00P\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00
对比
b'PK\x03\x04\x14\x00\x00\x00\x08\x003}\x15M\xf5\x8e\x0eH\xb9\x01\x00\x00I\x04\x00\x00\...docProps/app.xmlPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x003}\x15M\xa5\xc4\xa4$%\x01\x00\x00P\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x81E\x06\x00\x00docProps/core.xmlPK\x01\x02\x14\x03\
90%的字节是相同的,但有些是不同的。
我找了好几个小时都没找到问题所在。 奇怪的是,临时文件在这两种情况下都可以,但表示显示略有不同。
我也分析了 Requests,我发现了一个小区别:
<Request 'http://lsdev01/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1' [POST]>
{'environ': {'QUERY_STRING': ''
REQUEST_METHOD': 'POST'
CONTENT_TYPE': 'application/json'
CONTENT_LENGTH': '126'
REQUEST_URI': '/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1'
PATH_INFO': '/report/generate/DEMO_TECH_DEMO1'
DOCUMENT_ROOT': '/usr/share/nginx/html'
SERVER_PROTOCOL': 'HTTP/1.1'
REQUEST_SCHEME': 'http'
REMOTE_ADDR': '192.168.69.16'
REMOTE_PORT': '54436'
SERVER_PORT': '80'
SERVER_NAME': 'lsdev01'
HTTP_HOST': 'lsdev01'
HTTP_CONNECTION': 'keep-alive'
HTTP_CONTENT_LENGTH': '126'
HTTP_PRAGMA': 'no-cache'
HTTP_CACHE_CONTROL': 'no-cache'
HTTP_ACCEPT': 'application/json, text/plain, */*'
HTTP_ORIGIN': 'http://localhost:4213'
HTTP_AUTHORIZATION': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MzQ0OTM4MDksInN1YiI6eyIkJFVTUklETE9HSU4iOiIxNDQ5IiwiJCRVU1JOQU1FTE9HSU4iOiI5OSAtIHdlaXRlcmUgRmFjaGdydXBwZW4iLCIkJFVTUkNPREVMT0dJTiI6IkRXRSIsIiQkU0VTU0lPTkxPR0lEIjoxLCIkJFNJVEVJRCI6IjkwMDAwMDMyNzAiLCIkJFNJVEVHUlAiOiJMQUJPIiwiJCRURVNURkVBVFVSRUxJU1QiOiJURVNUUkVGTkVXXHUwMDFiTVVMVElERUJcdTAwMWJSRVRSSUVWRU5FV1x1MDAxYlJFU1JFRlx1MDAxYkxYUkJBQzJcdTAwMWJGQ1RURVNUXHUwMDFiQ09NVEVTVFx1MDAxYk5PTkVVTklRVUVCQ1x1MDAxYlBFUkZfTFhURVhUIiwiJCRMQU5HVUFHRSI6IiIsIkxBTkdVQUdFIjpudWxsfSwiZXhwIjoxNTM0NTgwMjA5LCJpbnN0YW5jZSI6ImRldiJ9.33Pid_GDPP6LUgoGzv_uU26QisBJNqoqsc7uTczdLvU'
HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
HTTP_CONTENT_TYPE': 'application/json'
HTTP_REFERER': 'http://localhost:4213/login'
HTTP_ACCEPT_ENCODING': 'gzip, deflate'
HTTP_ACCEPT_LANGUAGE': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7,fr;q=0.6'
SCRIPT_NAME': '/lx/ui_api/dev/dwe/dwe/reporting'
wsgi.input': <uwsgi._Input object at 0x7fd792236300>
wsgi.version': (1, 0)
wsgi.errors': <_io.TextIOWrapper name=2 mode='w' encoding='UTF-8'>
wsgi.run_once': False
wsgi.multithread': True
wsgi.multiprocess': False
wsgi.url_scheme': 'http'
uwsgi.version': b'2.0.15'
uwsgi.core': 3
uwsgi.node': b'lsdev01'
werkzeug.request': <Request 'http://lsdev01/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1' [POST]>}
shallow': False
view_args': {'reportCode': 'DEMO_TECH_DEMO1'}
url_rule': <Rule '/report/generate/<reportCode>' (OPTIONS, POST) -> report_generate>
_parsed_content_type': ('application/json', {})
stream': <werkzeug.wsgi.LimitedStream object at 0x7fd78f7d7438>
_cached_data': b'{"mimetype":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","input":{"header":"Test 1","footer":"Test 2"}}'
_cached_json': {'mimetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
input': {'header': 'Test 1'
footer': 'Test 2'}}
url': 'http://lsdev01/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1'}
对比
<Request 'http://lsdev01/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1' [POST]>
{'environ': {'QUERY_STRING': ''
REQUEST_METHOD': 'POST'
CONTENT_TYPE': 'application/json'
CONTENT_LENGTH': '126'
REQUEST_URI': '/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1'
PATH_INFO': '/report/generate/DEMO_TECH_DEMO1'
DOCUMENT_ROOT': '/usr/share/nginx/html'
SERVER_PROTOCOL': 'HTTP/1.1'
REQUEST_SCHEME': 'http'
REMOTE_ADDR': '192.168.69.18'
REMOTE_PORT': '55154'
SERVER_PORT': '80'
SERVER_NAME': 'lsdev01'
HTTP_HOST': 'lsdev01'
HTTP_ACCEPT_ENCODING': 'deflate, gzip'
HTTP_ACCEPT': 'application/json, text/plain, */*'
HTTP_REFERER': 'http://localhost:4213/login'
HTTP_ORIGIN': 'http://localhost:4213'
HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
HTTP_AUTHORIZATION': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MzQ0OTM4MDksInN1YiI6eyIkJFVTUklETE9HSU4iOiIxNDQ5IiwiJCRVU1JOQU1FTE9HSU4iOiI5OSAtIHdlaXRlcmUgRmFjaGdydXBwZW4iLCIkJFVTUkNPREVMT0dJTiI6IkRXRSIsIiQkU0VTU0lPTkxPR0lEIjoxLCIkJFNJVEVJRCI6IjkwMDAwMDMyNzAiLCIkJFNJVEVHUlAiOiJMQUJPIiwiJCRURVNURkVBVFVSRUxJU1QiOiJURVNUUkVGTkVXXHUwMDFiTVVMVElERUJcdTAwMWJSRVRSSUVWRU5FV1x1MDAxYlJFU1JFRlx1MDAxYkxYUkJBQzJcdTAwMWJGQ1RURVNUXHUwMDFiQ09NVEVTVFx1MDAxYk5PTkVVTklRVUVCQ1x1MDAxYlBFUkZfTFhURVhUIiwiJCRMQU5HVUFHRSI6IiIsIkxBTkdVQUdFIjpudWxsfSwiZXhwIjoxNTM0NTgwMjA5LCJpbnN0YW5jZSI6ImRldiJ9.33Pid_GDPP6LUgoGzv_uU26QisBJNqoqsc7uTczdLvU'
HTTP_CONTENT_TYPE': 'application/json'
HTTP_CONTENT_LENGTH': '126'
SCRIPT_NAME': '/lx/ui_api/dev/dwe/dwe/reporting'
wsgi.input': <uwsgi._Input object at 0x7fd792236300>
wsgi.version': (1, 0)
wsgi.errors': <_io.TextIOWrapper name=2 mode='w' encoding='UTF-8'>
wsgi.run_once': False
wsgi.multithread': True
wsgi.multiprocess': False
wsgi.url_scheme': 'http'
uwsgi.version': b'2.0.15'
uwsgi.core': 0
uwsgi.node': b'lsdev01'
werkzeug.request': <Request 'http://lsdev01/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1' [POST]>}
shallow': False
view_args': {'reportCode': 'DEMO_TECH_DEMO1'}
url_rule': <Rule '/report/generate/<reportCode>' (OPTIONS, POST) -> report_generate>
_parsed_content_type': ('application/json', {})
stream': <werkzeug.wsgi.LimitedStream object at 0x7fd78f7bcf98>
_cached_data': b'{"mimetype":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","input":{"header":"Test 1","footer":"Test 2"}}'
_cached_json': {'mimetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
input': {'header': 'Test 1'
footer': 'Test 2'}}
url': 'http://lsdev01/lx/ui_api/dev/dwe/dwe/reporting/report/generate/DEMO_TECH_DEMO1'}
不过没什么特别的...
有人知道问题出在哪里吗?
编辑:我也试过 send_files,但我遇到了同样的问题。
该死的!我知道了!
我在服务器端编码为 base64:
return Response(base64.b64encode(output), mimetype=mimetype)
在 angular 中,我结合了一些在 so 上找到的函数:
download(mimetype, data) {
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
var blob = new Blob([s2ab(atob(data))], {type: mimetype});
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
}
atob = 解码base64编码的字符串 s2ab = 字符串到 blob 的数组缓冲区
我认为这一切的根源是客户端和服务器之间的编码问题。但是我没有解释为什么!