Михаиллл
Михаиллл14 мая 2020 г. 8:41

Как через POST запрос отправить файл

Добрый день.
Пытаюсь в json запихнуть картинку и отправить, но получаю ошибку

413 Entity too large

Скажите пожалуйста, как все же отправить картинку POST запросом?

void AppCore::slotApiRequest(QByteArray data)
{
    QNetworkRequest request;
    request.setHeader( QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded" );
    request.setUrl(QUrl(urlServerForRequest));
    request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); //разрешает перенаправление
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");
    request.setHeader(QNetworkRequest::ContentLengthHeader,QByteArray::number(data.size()));
    myApiQuery.post(request, data);
}

void AppCore::addCategory(QString nameCategory, QString fileName)
{
    fileName = fileName.remove("file:///");
    //qDebug()<<nameCategory<<fileName;
    QImage myImage(fileName);

    QByteArray bArray;
    QBuffer buffer(&bArray);
    buffer.open(QIODevice::WriteOnly);
    myImage.save(&buffer, "BMP");
    QString imageString("data:image/bmp;base64,");
    imageString.append(QString::fromLatin1(bArray.toBase64().data()));
    //qDebug()<<imageString;

    QJsonObject jObj = QJsonObject{{"nameCategory", nameCategory}, {"image", imageString}};
    //QJsonObject jObj = QJsonObject{{"nameCategory", nameCategory}, {"image", fileName}};
    QJsonDocument doc = QJsonDocument(jObj);
    QByteArray arrayJson;
    QString strJson(doc.toJson(QJsonDocument::Compact));
    arrayJson += strJson;

    urlServerForRequest= urlServer + "addCategory";
    slotApiRequest(arrayJson);
}
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

16
Evgenii Legotckoi
  • 14 мая 2020 г. 8:46

Добрый день.

Это вам не C++ код копать нужно, а сервер настраивать. Если на сервере nginx, то настройте максимальный размер запроса.
Он вас просто отпинывает из-за слишком большого тела запроса.

Вот для максимального размера в 2 мб

client_max_body_size 2m;
    Evgenii Legotckoi
    • 14 мая 2020 г. 8:52

    Ну или уменьшайте размер изображения до того, который пропустит сервер.

      Михаиллл
      • 14 мая 2020 г. 9:05

      Я использую QtWebApp. Вы случайно не знаете, как в нем настраивать?

        Evgenii Legotckoi
        • 14 мая 2020 г. 9:10

        Глянул документацию, там нужно колупать структуру HttpConnectionHandlerSettings

        В ней есть поля maxRequestSize и maxMultipartSize

        • maxRequestSize - размер тела запроса
        • maxMultipartSize - размера запроса для изображений и прочей медия ерунды

        Поищите, как установить maxMultipartSize больше, чем 1048576

        В каком конкретно месте это делать, я не знаю. Но думаю, что-то такое при инициализации нужно настраивать

          Михаиллл
          • 14 мая 2020 г. 9:32
          • (ред.)

          Нашел эти настройки в файле .ini
          Сделал так, но почему то все равно запрос не доходит, и узнал что размер моего запроса 51321 символов.
          Скажите пожалуйста, в чем еще могут быть трудности?

          [listener]
          ; host=192.168.0.100
          port=8080
          minThreads=4
          maxThreads=100
          cleanupInterval=60000
          readTimeout=60000
          maxRequestSize=10000000
          maxMultiPartSize=10000000
          
          

          И ошибок не выдает, ту ошибку выдало только один раз, в остальных предыдущих случаях все проходило так же без ошибок.

            Evgenii Legotckoi
            • 14 мая 2020 г. 10:05

            Не понял фразу

            И ошибок не выдает, ту ошибку выдало только один раз, в остальных предыдущих случаях все проходило так же без ошибок.

            То есть ошибок нет, но загрузить не получается?

            узнал что размер моего запроса 51321 символов.

            Символов или байт? в зависимости от кодировки символ может занимать большее количество байт, чем один.

            Также ещё поменяйте заголовок запроса так (что-то я не обратил внимания сразу, вы ведь изображение грузите)

            request.setHeader( QNetworkRequest::ContentTypeHeader, "multipart/form-data" );
            
              Михаиллл
              • 14 мая 2020 г. 10:43

              Верно, ошибок нет, но загрузить не получается.
              Размер я узнаю методос QByteArray::size и вероятней всего получаю количество символов.
              Попробовал поменять заголовок, но результат тот же.
              Может быть как то иначе файлы нужно подгружать?

                Evgenii Legotckoi
                • 15 мая 2020 г. 3:03

                Вы у себя в коде дважды используете

                request.setHeader( QNetworkRequest::ContentTypeHeader, "" );
                

                Попробуйте убрать тот, что с application/json

                  Михаиллл
                  • 15 мая 2020 г. 3:11

                  Сделал так

                      QNetworkRequest request;
                      //request.setHeader( QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded" );
                      request.setUrl(QUrl(urlServerForRequest));
                      request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); //разрешает перенаправление
                      request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");
                      //request.setHeader( QNetworkRequest::ContentTypeHeader, "multipart/form-data" );
                      request.setHeader(QNetworkRequest::ContentLengthHeader,QByteArray::number(data.size()));
                      qDebug()<<data.size();
                      myApiQuery.post(request, data);
                  

                  и получил в первый раз ошибку

                  "413 Entity too large\r\n"
                  

                  а больше ошибок не выдавало, при этом запрос не проходит.
                  так тоже не работает, но ошибок не выдает

                      QNetworkRequest request;
                      //request.setHeader( QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded" );
                      request.setUrl(QUrl(urlServerForRequest));
                      request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); //разрешает перенаправление
                      //request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");
                      request.setHeader( QNetworkRequest::ContentTypeHeader, "multipart/form-data" );
                      request.setHeader(QNetworkRequest::ContentLengthHeader,QByteArray::number(data.size()));
                      qDebug()<<data.size();
                      myApiQuery.post(request, data);
                  
                    Evgenii Legotckoi
                    • 15 мая 2020 г. 3:17

                    всё... вот теперь у меня идеи закончились (((

                    Могу только предложить покопаться в исходника QtWebApp, посмотреть в каком случае появляется та ошибка и попытаться её исправить.

                    Ещё возможно, что саму пересылку изображения нужно как-то иначе паковать. То есть не через "data:image/bmp;base64,"

                      Михаиллл
                      • 15 мая 2020 г. 3:57
                      • (ред.)

                      Тут удобно смотреть и искать.
                      Ошибку выдает эта функция. Почему-то срабатывает условие (30 стр) "currentRequest->getStatus()==HttpRequest::abort"

                      void HttpConnectionHandler::read()
                       {
                           // The loop adds support for HTTP pipelinig
                           while (socket->bytesAvailable())
                           {
                               #ifdef SUPERVERBOSE
                                   qDebug("HttpConnectionHandler (%p): read input",static_cast<void*>(this));
                               #endif
                      
                               // Create new HttpRequest object if necessary
                               if (!currentRequest)
                               {
                                   currentRequest=new HttpRequest(settings);
                               }
                      
                               // Collect data for the request object
                               while (socket->bytesAvailable() && currentRequest->getStatus()!=HttpRequest::complete && currentRequest->getStatus()!=HttpRequest::abort)
                               {
                                   currentRequest->readFromSocket(socket);
                                   if (currentRequest->getStatus()==HttpRequest::waitForBody)
                                   {
                                       // Restart timer for read timeout, otherwise it would
                                       // expire during large file uploads.
                                       int readTimeout=settings->value("readTimeout",10000).toInt();
                                       readTimer.start(readTimeout);
                                   }
                               }
                      
                               // If the request is aborted, return error message and close the connection
                               if (currentRequest->getStatus()==HttpRequest::abort)
                               {
                                   socket->write("HTTP/1.1 413 entity too large\r\nConnection: close\r\n\r\n413 Entity too large\r\n");
                                   while(socket->bytesToWrite()) socket->waitForBytesWritten();
                                   socket->disconnectFromHost();
                                   delete currentRequest;
                                   currentRequest=nullptr;
                                   return;
                               }
                      
                               // If the request is complete, let the request mapper dispatch it
                               if (currentRequest->getStatus()==HttpRequest::complete)
                               {
                                   readTimer.stop();
                                   qDebug("HttpConnectionHandler (%p): received request",static_cast<void*>(this));
                      
                                   // Copy the Connection:close header to the response
                                   HttpResponse response(socket);
                                   bool closeConnection=QString::compare(currentRequest->getHeader("Connection"),"close",Qt::CaseInsensitive)==0;
                                   if (closeConnection)
                                   {
                                       response.setHeader("Connection","close");
                                   }
                      
                                   // In case of HTTP 1.0 protocol add the Connection:close header.
                                   // This ensures that the HttpResponse does not activate chunked mode, which is not spported by HTTP 1.0.
                                   else
                                   {
                                       bool http1_0=QString::compare(currentRequest->getVersion(),"HTTP/1.0",Qt::CaseInsensitive)==0;
                                       if (http1_0)
                                       {
                                           closeConnection=true;
                                           response.setHeader("Connection","close");
                                       }
                                   }
                      
                                   // Call the request mapper
                                   try
                                   {
                                       requestHandler->service(*currentRequest, response);
                                   }
                                   catch (...)
                                   {
                                       qCritical("HttpConnectionHandler (%p): An uncatched exception occured in the request handler",
                                                 static_cast<void*>(this));
                                   }
                      
                                   // Finalize sending the response if not already done
                                   if (!response.hasSentLastPart())
                                   {
                                       response.write(QByteArray(),true);
                                   }
                      
                                   qDebug("HttpConnectionHandler (%p): finished request",static_cast<void*>(this));
                      
                                   // Find out whether the connection must be closed
                                   if (!closeConnection)
                                   {
                                       // Maybe the request handler or mapper added a Connection:close header in the meantime
                                       bool closeResponse=QString::compare(response.getHeaders().value("Connection"),"close",Qt::CaseInsensitive)==0;
                                       if (closeResponse==true)
                                       {
                                           closeConnection=true;
                                       }
                                       else
                                       {
                                           // If we have no Content-Length header and did not use chunked mode, then we have to close the
                                           // connection to tell the HTTP client that the end of the response has been reached.
                                           bool hasContentLength=response.getHeaders().contains("Content-Length");
                                           if (!hasContentLength)
                                           {
                                               bool hasChunkedMode=QString::compare(response.getHeaders().value("Transfer-Encoding"),"chunked",Qt::CaseInsensitive)==0;
                                               if (!hasChunkedMode)
                                               {
                                                   closeConnection=true;
                                               }
                                           }
                                       }
                                   }
                      
                                   // Close the connection or prepare for the next request on the same connection.
                                   if (closeConnection)
                                   {
                                       while(socket->bytesToWrite()) socket->waitForBytesWritten();
                                       socket->disconnectFromHost();
                                   }
                                   else
                                   {
                                       // Start timer for next request
                                       int readTimeout=settings->value("readTimeout",10000).toInt();
                                       readTimer.start(readTimeout);
                                   }
                                   delete currentRequest;
                                   currentRequest=nullptr;
                               }
                           }
                       }
                      
                        Evgenii Legotckoi
                        • 15 мая 2020 г. 4:07
                        • Ответ был помечен как решение.

                        Мне ещё одна мысль в голову пришла, попробуйте связаться с автором библиотеки.
                        Вроде адекватный малый, я ему в 2016-м году исправление посылал. Он быстро среагировал.
                        Может у него есть готовый пример для загрузки файла. Естественно писать ему нужно на английском.

                          Михаиллл
                          • 15 мая 2020 г. 4:22

                          Написал ему. А как долго он вам отвечал? И как думаете, в какую сторону кода стоит копать?

                            Evgenii Legotckoi
                            • 15 мая 2020 г. 4:26

                            Тогда он мне ответил вроде бы в течение пары дней.
                            Вполне возможно, что нужно правильно сформировать данные с изображением.
                            Также всё-таки может быть проблема со стороны сервера...
                            Но у меня не было никогда задачи делать загрузку изображения через QNetworkAccessManager и тем более делать этот на сервер с QtWebApp.
                            Поэтому я только предполагал возможные проблемы, но видимо там есть какой-то нюанс, который я не могу понять.

                              Михаиллл
                              • 16 мая 2020 г. 4:23

                              Скажите пожалуйста, как с помощью отладчика понять, загружен ли .ini файл?

                                Михаиллл
                                • 16 мая 2020 г. 5:11
                                • (ред.)

                                Оказалось в startup.cpp нужно в

                                /** Name of this application */
                                #define APPNAME "HttpSerwerQtWebAppGameTamada"
                                

                                не забыть поменять имя, тогда инициализация проходит и сервер нормально работает

                                  Комментарии

                                  Только авторизованные пользователи могут публиковать комментарии.
                                  Пожалуйста, авторизуйтесь или зарегистрируйтесь
                                  AD

                                  C++ - Тест 004. Указатели, Массивы и Циклы

                                  • Результат:50баллов,
                                  • Очки рейтинга-4
                                  m
                                  • molni99
                                  • 26 октября 2024 г. 11:37

                                  C++ - Тест 004. Указатели, Массивы и Циклы

                                  • Результат:80баллов,
                                  • Очки рейтинга4
                                  m
                                  • molni99
                                  • 26 октября 2024 г. 11:29

                                  C++ - Тест 004. Указатели, Массивы и Циклы

                                  • Результат:20баллов,
                                  • Очки рейтинга-10
                                  Последние комментарии
                                  ИМ
                                  Игорь Максимов22 ноября 2024 г. 22:51
                                  Django - Урок 017. Кастомизированная страница авторизации на Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
                                  Evgenii Legotckoi
                                  Evgenii Legotckoi1 ноября 2024 г. 0:37
                                  Django - Урок 064. Как написать расширение для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
                                  A
                                  ALO1ZE19 октября 2024 г. 18:19
                                  Читалка fb3-файлов на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
                                  ИМ
                                  Игорь Максимов5 октября 2024 г. 17:51
                                  Django - Урок 064. Как написать расширение для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
                                  d
                                  dblas55 июля 2024 г. 21:02
                                  QML - Урок 016. База данных SQLite и работа с ней в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                                  Сейчас обсуждают на форуме
                                  Evgenii Legotckoi
                                  Evgenii Legotckoi25 июня 2024 г. 1:11
                                  добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
                                  t
                                  tonypeachey115 ноября 2024 г. 17:04
                                  google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
                                  NSProject
                                  NSProject4 июня 2022 г. 13:49
                                  Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
                                  9
                                  9Anonim25 октября 2024 г. 19:10
                                  Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

                                  Следите за нами в социальных сетях