Михаиллл
Михаиллл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
                                  AD

                                  C ++ - Test 004. Pointers, Arrays and Loops

                                  • Result:50points,
                                  • Rating points-4
                                  m

                                  C ++ - Test 004. Pointers, Arrays and Loops

                                  • Result:80points,
                                  • Rating points4
                                  m

                                  C ++ - Test 004. Pointers, Arrays and Loops

                                  • Result:20points,
                                  • Rating points-10
                                  Last comments
                                  ИМ
                                  Игорь МаксимовNov. 22, 2024, 11:51 a.m.
                                  Django - Tutorial 017. Customize the login page to Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
                                  Evgenii Legotckoi
                                  Evgenii LegotckoiOct. 31, 2024, 2:37 p.m.
                                  Django - Lesson 064. How to write a Python Markdown extension Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
                                  A
                                  ALO1ZEOct. 19, 2024, 8:19 a.m.
                                  Fb3 file reader on Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
                                  ИМ
                                  Игорь МаксимовOct. 5, 2024, 7:51 a.m.
                                  Django - Lesson 064. How to write a Python Markdown extension Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
                                  d
                                  dblas5July 5, 2024, 11:02 a.m.
                                  QML - Lesson 016. SQLite database and the working with it in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                                  Now discuss on the forum
                                  Evgenii Legotckoi
                                  Evgenii LegotckoiJune 24, 2024, 3:11 p.m.
                                  добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
                                  t
                                  tonypeachey1Nov. 15, 2024, 6:04 a.m.
                                  google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
                                  NSProject
                                  NSProjectJune 4, 2022, 3:49 a.m.
                                  Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
                                  9
                                  9AnonimOct. 25, 2024, 9:10 a.m.
                                  Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

                                  Follow us in social networks