使用laravel我将二进制数据发送到客户端,稍后将其保存到客户端的计算机。 我正在使用ajax并传输内容。 这是我从服务器发送的内容:
$fileRecord = File::findOrFail($fileId);
set_time_limit(0);
$fs = Storage::disk('local')->getDriver();
$metaData = $fs->getMetadata($fileRecord->getFilePath());
$fileStream = $fs->readStream($fileRecord->getFilePath());
return response()->stream(function () use ($fileStream) {
while(@ob_end_clean());
fpassthru($fileStream);
}, 200, [
'Content-Transfer-Encoding' => 'binary',
'Content-Type' => $metaData['type'],
'Content-Disposition' => "attachment; filename=\"{$fileRecord->getFullFileName()}\"",
]);
我解决了与数据大小相关的几个问题,如提到here。
但是我无法在客户端上获得正确的文件内容。我尝试将内容保存到服务器上的其他文件中,一切正常。
以下是我得到的样本(样本从开头到某个字符列出一段文件):
Ex 1. png
image
这应该是:
89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 06 40 00 00 04 B0 08 02 00 00 00 2C 63 11 C0 00 00 00 04 67 41 4D 41 00 00 D6 D8 D4 4F 58 32 00 00 00 19 74 45 58 74 53 6F 66 74 77 61 72 65 00 41 64 6F 62 65 20 49 6D 61 67 65 52 65 61 64 79 71 C9 65 3C 00 07 8D 52 49 44 41 54
这就是生成的内容:
从devTools复制到文件:
C2 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 06 40 00 00 04 C2 B0 08 02 00 00 00 2C 63 11 C3 80 00 00 00 04 67 41 4D 41 00 00 C3 96 C3 98 C3 94 4F 58 32 00 00 00 19 74 45 58 74 53 6F 66 74 77 61 72 65 00 41 64 6F 62 65 20 49 6D 61 67 65 52 65 61 64 79 71 C3 89 65 3C 00 07 C2 8D 52 49 44 41 54
浏览器将数据作为客户端上的文件下载后:
EF BF BD 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 06 40 00 00 04 EF BF BD 08 02 00 00 00 2C 63 11 EF BF BD 00 00 00 04 67 41 4D 41 00 00 EF BF BD EF BF BD EF BF BD 4F 58 32 00 00 00 19 74 45 58 74 53 6F 66 74 77 61 72 65 00 41 64 6F 62 65 20 49 6D 61 67 65 52 65 61 64 79 71 EF BF BD 65 3C 00 07 EF BF BD 52 49 44 41 54
Ex 2. pdf
档案
这应该是:
25 50 44 46 2D 31 2E 35 0D 0A 25 B5 B5 B5 B5 0D 0A 31 20 30 20 6F 62 6A 0D 0A 3C 3C 2F 54 79 70 65 2F 43 61 74 61 6C 6F 67 2F 50 61 67 65 73 20 32 20 30 20 52 2F 4C 61 6E 67 28 65 6E 2D 55 53 29 20 2F 53 74 72 75 63 74 54 72 65 65 52 6F 6F 74 20 33 31
这就是生成的内容:
从devTools手动复制到文件:
25 50 44 46 2D 31 2E 35 0D 0A 25 C2 B5 C2 B5 C2 B5 C2 B5 0D 0A 31 20 30 20 6F 62 6A 0D 0A 3C 3C 2F 54 79 70 65 2F 43 61 74 61 6C 6F 67 2F 50 61 67 65 73 20 32 20 30 20 52 2F 4C 61 6E 67 28 65 6E 2D 55 53 29 20 2F 53 74 72 75 63 74 54 72 65 65 52 6F 6F 74 20 33 31
浏览器将数据作为客户端上的文件下载后:
25 50 44 46 2D 31 2E 35 0D 0A 25 EF BF BD EF BF BD EF BF BD EF BF BD 0D 0A 31 20 30 20 6F 62 6A 0D 0A 3C 3C 2F 54 79 70 65 2F 43 61 74 61 6C 6F 67 2F 50 61 67 65 73 20 32 20 30 20 52 2F 4C 61 6E 67 28 65 6E 2D 55 53 29 20 2F 53 74 72 75 63 74 54 72 65 65 52 6F 6F 74 20 33 31
我在客户端上获得的一些标题(chrome devTools):
对于png文件:
Content-Disposition:attachment;filename="8c4d44a0-3bd9-11e7-8e6a-4ff287c4841c.png"
Content-Length:739993
Content-Transfer-Encoding:binary
Content-Type:image/png; charset=utf-8
对于pdf文件:
Content-Disposition:attachment; filename="e88fd450-3bd8-11e7-9dfa-99b21f936329.pdf"
Content-Length:420639
Content-Transfer-Encoding:binary
Content-Type:application/pdf; charset=utf-8
P.S。您可以看到格式错误的数据中存在C2
个字符或EF BF BD
字符序列。所以在我看来这是一个编码问题。我尝试在字符串上使用utf8_encode
,但无济于事。文件句柄上的mb_detect_encoding
返回空字符串。
我做错了什么?
P.P.S。在客户端上,我使用以下方式从ajax获取的二进制数据:
saveAs(new Blob([ajaxData], { type: mimeType }), fileName);
答案 0 :(得分:0)
我终于弄清楚它是什么。
显然你不能直接将二进制数据输入javascript中的Blob
对象(至少对于pdf,pngs,jpegs它不起作用),但是必须使用这样的东西:
function binaryToUint8Arr (bin) {
var length = bin.length;
var buf = new ArrayBuffer(length);
var arr = new Uint8Array(buf);
for (var i = 0; i < length; i++) {
arr[i] = bin.charCodeAt(i);
}
return buf;
}
我基本上需要将原始二进制文件包装在arraybuffer中和 将二进制字符转换为Unicode
所以我的代码变成了:
saveAs(new Blob([binaryToUint8Arr(ajaxData)], { type: mimeType }), fileName);
(其中ajaxData
是我从ajax获得的二进制数据)