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.
16

Добрый день.

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

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

client_max_body_size 2m;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

request.setHeader( QNetworkRequest::ContentTypeHeader, "multipart/form-data" );

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

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

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

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

Сделал так

    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);

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

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

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

Тут удобно смотреть и искать.
Ошибку выдает эта функция. Почему-то срабатывает условие (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;
         }
     }
 }

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

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

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

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

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

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

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

Comments

Only authorized users can post comments.
Please, Log in or Sign up
How to become an author?

Contribute to the evolution of the EVILEG community.

Learn how to become a site author.

Learn it
Donate

Good day, Dear Users!!!

I am Evgenii Legotckoi, developer of EVILEG. And it is my hobby project, which helps to learn programming another programmers and developers

If the site helped you, and you want also support the development of the site, than you can donate by following ways

PayPalYandex.Money
Timeweb

Let me recommend you the excellent hosting on which EVILEG is located.

For many years, Timeweb has been proving his stability.

For projects on Django I recommend VDS hosting

View Hosting Timeweb
s
June 3, 2020, 2:56 a.m.
silo1995

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

  • Result:35points,
  • Rating points-10
AP
June 2, 2020, 10:11 p.m.
Aleksej Pikenin

C++ - Test 005. Structures and Classes

  • Result:75points,
  • Rating points2
June 2, 2020, 2:04 p.m.
Daniil Chizhevskij

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

  • Result:86points,
  • Rating points6
Last comments
June 5, 2020, 2:39 a.m.
Evgenij Legotskoj

Qt/C++ - Tutorial 091. How to write a custom delegate controlling the highlighting of a row in a table

По-моему, смысла в этом нет особого. Если делегат будет игнорировать настройки таблицы, то это приведёт ещё к большему непониманию, что вообще происходит, для программиста, который после вас буд…
June 5, 2020, 2:34 a.m.
IscanderChe

Qt/C++ - Tutorial 091. How to write a custom delegate controlling the highlighting of a row in a table

Сижу, размышляю: можно ли переписать делегата так, чтобы независимо от настроек строк выделялись строки?
June 5, 2020, 2:31 a.m.
Evgenij Legotskoj

Qt/C++ - Tutorial 091. How to write a custom delegate controlling the highlighting of a row in a table

Понятно. Я не обратил внимания на то, что там было в старом коде по настройкам строк :)
June 5, 2020, 2:27 a.m.
IscanderChe

Qt/C++ - Tutorial 091. How to write a custom delegate controlling the highlighting of a row in a table

Разобрался. У вас изначально в проекте были вот эти настройки: ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);ui->tableView->setSelectionMode(QAbstractItemVie…
June 4, 2020, 12:10 p.m.
IscanderChe

Qt/C++ - Tutorial 091. How to write a custom delegate controlling the highlighting of a row in a table

Полностью скопировал пример - всё правильно работает. Значит, где-то у меня ошибки в тестовом проекте. Буду разбираться. Извините за беспокойство. :)
Now discuss on the forum
MA
June 4, 2020, 3:46 a.m.
Mihail A

Qt- C++ QTableView подсветить строку

Спасибо.
f
June 3, 2020, 2:49 a.m.
fryn3

Можно ли сделать в QML таблицу как в Excel?

edi-tableview - нашел пока такое выглядит коряво, посмотрим что можно сделать
June 2, 2020, 3:46 a.m.
Evgenij Legotskoj

Медиа файлы Google Firebase

Картинки можете попробовать сжимать через QPixmap, там есть возможность установки scaleFactor, через него можете устанавливать нужные параметры. А что касается конвертации видео, то лучше п…
June 2, 2020, 3:01 a.m.
Evgenij Legotskoj

Перехват обращения к локальным файлам QWebEngineView

В вашем случае вполне адекватное решение. Так сказать меньше зло. В противном случае пришлось бы очень много переписывать и перепиливать.
a
June 1, 2020, 11:26 a.m.
alekseyttrv

SSL на Android

у меня стоит версия Qt 5.14.2. В настройках android поставил openssl из коробки, и этот прроект автоматически стянулся. Достаточно было только добавить в .pro-файл строку после этого и все …
About
Services
© EVILEG 2015-2020
Recommend hosting TIMEWEB