Задать вопрос
@Artikul2

PHP Fatal error: Allowed memory exhausted при загрузке JSON в API?

Отправляю POST запрос, который в теле содержит JSON данные, всего около 150 мегабайт. Получаю ошибку PHP Fatal error: Allowed memory exhausted. Делал увеличение памяти для php со 128 до 1024, но ошибка не ушла.
Файлы размером около 50 мегабайт, нормально загружаются.

Я написал свое API в Ларавел. После route данные приходят на контролер
public function createCustomer(Request $request)
    {
        $data = file_get_contents('php://input');
        $response = $this->customerLoad->handle($data);
        return response()->json($response, 202);
    }

Далее попадают в другой файл, в логику
class CustomerLoad
{
    public function handle($data)
    {
        $jsonFilePath = $this->saveJsonToFile($data);
    }
    private function saveJsonToFile($data)
    {
        $fileName = Str::uuid() . '.json';
        $filePath = 'upload/partners/json/' . $fileName;
        Storage::put($filePath, $data);
        return $filePath;
    }
}

И далее попадает в файл из папки jobs, где я беру с диска json с помощью rabbit и записываю в базу данных.
Мой ларавел сообщает об ошибке
в файле \vendor\laravel\framework\src\Illuminate\Http\Request.php в строке
$this->json = new InputBag((array) json_decode($this->getContent(), true));

Полная функция такая
public function json($key = null, $default = null)
    {
        if (! isset($this->json)) {
            $this->json = new InputBag((array) json_decode($this->getContent(), true));
        }
        if (is_null($key)) {
            return $this->json;
        }
        return data_get($this->json->all(), $key, $default);
    }

nginx отдает 200 на post запрос, в логах PHP message: PHP Fatal error: Allowed memory size of 536870912 bytes exhausted

Я полагаю, что json из post запроса читается построчно, видимо, и это вызывает ошибку, если не хватает памяти (хотя я ее увеличивал в php).
Можно ли сделать, чтобы json не читался php в память из body запроса, ведь задача - просто взять данные как есть и положить на диск?
  • Вопрос задан
  • 231 просмотр
Подписаться 1 Простой 18 комментариев
Решения вопроса 1
Fragster
@Fragster
помогло? отметь решением!
Проблема как раз не в том, что чтение идет построчно, а в том, что оно сразу весь файл хочет превратить в структуру в памяти.
Можно воспользоваться чем-то типа https://github.com/pcrov/JsonReader/wiki/JsonReader-API чтобы читать поэлементно и запихивать прочитанное в базу, без запихивания всего гигантского файла в память.

UPD: для того, чтобы сам laravel не переводил тело запроса в json - нужно указать в запросе на отправляющей стороне Content-Type: text/plain. После этого входящий поток можно получить через $request->getContent(true) и сделать с ним что надо - либо перенаправить в файл, чтобы потом обработать, либо сразу читать через JsonReader

чуть более долгая модификация отправляющей стороны - переделать запрос на multipart с передачей файла и обрабатывать request->file()
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы