Из своего внешнего интерфейса Vue я загружаю файл .glb с почтовым запросом в свой бэкэнд Laravel. Файл прекрасно доходит туда, однако мне нужно передать его дальше API, который сохраняет его в базе данных в виде двоичного файла.
Вот много вариантов, которые я пробовал, а гораздо больше уже удалено. Сначала я пытался отправить сам файл, но потом я заметил, что исходный файл размером 5 МБ, который по-прежнему был 5 МБ на бэкэнде, был всего 1 байт на API, поэтому он не прошел. Затем я попытался опубликовать сами двоичные данные, чтобы API не нужно было получать содержимое файла, а просто сохранял входящие данные в базу данных. Я получал Malformed utf-8 characters от json_encode на бэкенде, теперь я получаю ту же ошибку на стороне API. И затем, когда, к счастью, в некоторых вариантах нет ошибки неправильного формата utf-8, я узнаю, что файл снова вернулся к 1B (пустой).
Внутренний код:
public function uploadBinary(Request $r, $id)
{
$file = $r->file('file');
$bin = $file->get();
// $bin = mb_convert_encoding($bin, 'UTF-8', 'auto');
// $file->storePubliclyAs('', 'glbtest.glb');
$res = Http::withToken(config('api.key'))
->acceptJson()
->withHeaders([
// 'Content-Type' => 'model/gltf-binary'
'Content-Type' => 'application/octet-stream'
])
// ->withBody($bin, 'application/octet-stream')
->asMultipart()
// ->attach('file', asset('glbtest.glb'))
// ->post(replaceWildcards(config('api.urls.tdmodels.binary'), compact('id')));
// ->post(replaceWildcards(config('api.urls.tdmodels.binary'), compact('id')), $bin);
->post(replaceWildcards(config('api.urls.tdmodels.binary'), compact('id')), [
'file' => $bin
// 'file' => file_get_contents(storage_path('app/glbtest.glb'))
]);
return response()->json([
'message' => 'uplo',
'body' => $res->body(),
'sizebe' => $file->getSize(),
'pathbe' => $file->path(),
'asset' => asset('glbtest.glb'),
]);
}
API-код:
public function uploadBinary($id, Request $request)
{
// $request->setJson(null);
$tdmodel = Tdmodel::findOrFail($id);
// $binaryData = $request->getContent();
// $file = $request->file('file');
// $binaryData = $file->getContent();
// $tdmodel->binary_file = $request->getContent();
// $tdmodel->binary_file = $binaryData;
$tdmodel->binary_file = $request->file;
$tdmodel->save();
return response()->json([
'message' => 'Binary file uploaded successfully',
// 'fileAPI' => $file->getSize()
]);
}
Могу ли я отправить сам файл, но я что-то упускаю? Могу ли я отправить двоичный файл без Http Laravel, пытающегося кодировать и декодировать данные json? Я чувствую, что у этого должно быть простое решение, но я уже потратил на это два дня. Спасибо.
После еще нескольких тестов я получил версию, которая загружает в API целых 5 МБ, однако в базу данных загружается только 16 МБ. Я также проверил свой файл my.ini, где достаточно большой колпачок с помощью max_allowed_packet=512M.
Серверная часть:
public function uploadBinary(Request $r, $id)
{
$file = $r->file('file');
$bin = $file->get();
$res = Http::withToken(config('api.key'))
->acceptJson()
->withBody($bin, 'application/octet-stream')
->post(replaceWildcards(config('api.urls.tdmodels.binary'), compact('id')));
return response()->json([
'message' => 'uplo',
'body' => $res->body(),
'sizebe' => $file->getSize(),
]);
}
API:
public function uploadBinary($id, Request $request)
{
$tdmodel = Tdmodel::findOrFail($id);
$binaryData = $request->getContent();
$stream = fopen('php://memory', 'r+');
fwrite($stream, $binaryData);
rewind($stream);
$tdmodel->binary_file = $stream;
$tdmodel->save();
return response()->json([
'message' => 'Binary file uploaded successfully',
'binlen' => strlen($binaryData),
'fstat' => fstat($stream),
]);
sizebe из бэкенда имеет значение 5224096
затем из ответа API
binlen:5224096fstat\":{\"0\":12,\"1\":0,\"2\":33206,\"3\":1,\"4\":0,\"5\":0,\"6\":-1,\"7\":5224096,\"8\":0,\"9\":0,\"10\":0,\"11\":-1,\"12\":-1,\"dev\":12,\"ino\":0,\"mode\":33206,\"nlink\":1,\"uid\":0,\"gid\":0,\"rdev\":-1,\"size\":5224096,\"atime\":0,\"mtime\":0,\"ctime\":0,\"blksize\":-1,\"blocks\":-1}}
что означает, что я, наконец, получаю правильный двоичный размер на стороне API, как в двоичном содержимом запроса, так и в потоке, в который я его перемещаю. а в базе пока только это:






Итак, я в конце концов просто использовал guzzle, и все заработало. 3 дня работы в мусорном ведре.
public function uploadBinary(Request $r, $id)
{
if (!$r->hasFile('file')) {
return response()->json([
'message' => 'Binary data not found'
], 404);
}
$file = $r->file('file');
$binary = $file->get();
$client = new Client();
$headers = [
'Authorization' => config('api.key_bearer'),
'Content-Type' => 'application/octet-stream',
];
$res = $client->request('POST', replaceWildcards(config('api.urls.tdmodels.binary'), compact('id')), [
'headers' => $headers,
'body' => $binary,
]);
return response()->json([
'message' => 'Uploaded successfully.',
]);
}