Михаиллл
МихаилллМамыр 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"
                                

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

                                  Пікірлер

                                  Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
                                  Кіріңіз немесе Тіркеліңіз
                                  Г

                                  C++ - Тест 001. Первая программа и типы данных

                                  • Нәтиже:66ұпай,
                                  • Бағалау ұпайлары-1
                                  t

                                  C++ - Тест 001. Первая программа и типы данных

                                  • Нәтиже:33ұпай,
                                  • Бағалау ұпайлары-10
                                  t

                                  Qt - Тест 001. Сигналы и слоты

                                  • Нәтиже:52ұпай,
                                  • Бағалау ұпайлары-4
                                  Соңғы пікірлер
                                  G
                                  GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
                                  Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
                                  d
                                  dblas5Шілде 5, 2024, 11:02 Т.Ж.
                                  QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                                  k
                                  kmssrАқп. 8, 2024, 6:43 Т.Қ.
                                  Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                  АК
                                  Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
                                  Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                  Енді форумда талқылаңыз
                                  Evgenii Legotckoi
                                  Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
                                  добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
                                  F
                                  FynjyШілде 22, 2024, 4:15 Т.Ж.
                                  при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
                                  BlinCT
                                  BlinCTМаусым 25, 2024, 1 Т.Ж.
                                  Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
                                  BlinCT
                                  BlinCTМамыр 5, 2024, 5:46 Т.Ж.
                                  Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
                                  Evgenii Legotckoi
                                  Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
                                  Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

                                  Бізді әлеуметтік желілерде бақылаңыз