Михаиллл
МихаилллMay 14, 2020, 8:41 a.m.

Как через 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);
}
We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

16
Evgenii Legotckoi
  • May 14, 2020, 8:46 a.m.

Добрый день.

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

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

client_max_body_size 2m;
    Evgenii Legotckoi
    • May 14, 2020, 8:52 a.m.

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

      Михаиллл
      • May 14, 2020, 9:05 a.m.

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

        Evgenii Legotckoi
        • May 14, 2020, 9:10 a.m.

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

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

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

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

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

          Михаиллл
          • May 14, 2020, 9:32 a.m.
          • (edited)

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

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

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

            Evgenii Legotckoi
            • May 14, 2020, 10:05 a.m.

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

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

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

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

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

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

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

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

                Evgenii Legotckoi
                • May 15, 2020, 3:03 a.m.

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

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

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

                  Михаиллл
                  • May 15, 2020, 3:11 a.m.

                  Сделал так

                      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
                    • May 15, 2020, 3:17 a.m.

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

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

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

                      Михаиллл
                      • May 15, 2020, 3:57 a.m.
                      • (edited)

                      Тут удобно смотреть и искать.
                      Ошибку выдает эта функция. Почему-то срабатывает условие (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
                        • May 15, 2020, 4:07 a.m.
                        • The answer was marked as a solution.

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

                          Михаиллл
                          • May 15, 2020, 4:22 a.m.

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

                            Evgenii Legotckoi
                            • May 15, 2020, 4:26 a.m.

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

                              Михаиллл
                              • May 16, 2020, 4:23 a.m.

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

                                Михаиллл
                                • May 16, 2020, 5:11 a.m.
                                • (edited)

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

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

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

                                  Comments

                                  Only authorized users can post comments.
                                  Please, Log in or Sign up
                                  e
                                  • ehot
                                  • April 1, 2024, 2:29 a.m.

                                  C++ - Тест 003. Условия и циклы

                                  • Result:78points,
                                  • Rating points2
                                  B

                                  C++ - Test 002. Constants

                                  • Result:16points,
                                  • Rating points-10
                                  B

                                  C++ - Test 001. The first program and data types

                                  • Result:46points,
                                  • Rating points-6
                                  Last comments
                                  k
                                  kmssrFeb. 9, 2024, 7:43 a.m.
                                  Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                  Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                  EVA
                                  EVADec. 25, 2023, 11:30 p.m.
                                  Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
                                  J
                                  JonnyJoDec. 25, 2023, 9:38 p.m.
                                  Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
                                  G
                                  GvozdikDec. 19, 2023, 10:01 a.m.
                                  Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
                                  Now discuss on the forum
                                  a
                                  a_vlasovApril 14, 2024, 6:41 p.m.
                                  Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
                                  Павел Дорофеев
                                  Павел ДорофеевApril 14, 2024, 2:35 p.m.
                                  QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
                                  f
                                  fastrexApril 4, 2024, 4:47 p.m.
                                  Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…
                                  AC
                                  Alexandru CodreanuJan. 20, 2024, 12:57 a.m.
                                  QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…

                                  Follow us in social networks