‹Нечетливо› за POST дължина на тялото от 100 000 байта или повече, също с blob/FormData

РЕДАКТИРАНЕ: eis беше прав, имаше смущаващ (Netbeans) дебъгер.

Клиентът изпраща някои данни към сървлета на Spring Boot:

        fetch("/command", {
            method: 'POST',
            cache: 'no-cache',
            headers: {
              'Content-Type': 'application/json'
            },
            body: JSON.stringify(...)
        });

От страната на сървъра HttpServletRequest.getReader() връща низ <Unreadable> (този точно изписване и без друга грешка или изключение) вместо JSON низа, изпратен от клиента. Точно същото се случва и за 'Content-Type': 'text/plain; charset=UTF-8'. JSON низът има около 150 kB и на пръв поглед, регистриран в конзолата на браузъра, преди да бъде изпратен, изглежда като едноредов JSON низ.

За тестове изпратих съдържанието на текстово поле от няколко kB вместо JSON низа. Този път сървърът получи идентичен низ без проблеми. Само JSON низът може да бъде изпратен по някаква причина. Тествах дали ограничаването на размера му помага. Както се оказа, това работи:

body: JSON.stringify(...).substring(0,99999)

но това не:

body: JSON.stringify(...).substring(0,100000)

Следното:

body: new Blob( [ contentsCallback().substring(0, N) ], { type: 'application/json' } )

работи за N‹100 000. Това:

const formData = new FormData();
formData.append('blob', new Blob( [ JSON.stringify(...).substring(0, N) ], { type: 'application/json' } ), 'test');
...
body: formData

работи за N‹99823.

Изглежда някъде има ограничение на размера. Не знам дали е от страната на клиента или сървъра. Това е фрагмент от application.properties на сървъра, където поставям различни свойства, обсъждани тук :

multipart.max-file-size=20MB
multipart.max-request-size=20MB
spring.servlet.multipart.max-file-size=20MB
spring.servlet.multipart.max-request-size=20MB
multipart.maxFileSize=20Mb
multipart.maxRequestSize=20Mb
server.tomcat.max-http-post-size=10000000
server.tomcat.max-http-post-size=100000000
server.tomcat.max-swallow-size=100000000

Ето как се регистрира сървлетът:

@Bean
public ServletRegistrationBean commandRegistration() {
    ServletRegistrationBean bean = new ServletRegistrationBean(
            new CommandServlet(), "/command");
    // final int SIZE_LIMIT = 20000000;
    // MultipartConfigElement mc = new MultipartConfigElement(TMP_FOLDER, 
    //         SIZE_LIMIT, SIZE_LIMIT * 2, SIZE_LIMIT / 2);
    // bean.setMultipartConfig(mc);
    return bean;
}

Разкоментирането на коментираната част не променя въпросния лимит.

Ето данните на Chrome за fetch(), който изпраща пълния 150kB JSON (получен като <Unreadable>):

Request URL: https://localhost:8443/?command=save
Request Method: POST
Status Code: 200 
Remote Address: [::1]:8443
Referrer Policy: strict-origin-when-cross-origin
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Length: 0
Content-Type: text/html;charset=UTF-8
Date: Thu, 18 Mar 2021 09:32:00 GMT
Expires: 0
Keep-Alive: timeout=60
Pragma: no-cache
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,pl;q=0.8,de;q=0.7,fr;q=0.6,ru;q=0.5,es;q=0.4,nl;q=0.3,cs;q=0.2,it;q=0.1,nb;q=0.1
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 146111
Content-Type: application/json
Cookie: JSESSIONID=961B41156DCF6F7C57455AA871525198; JSESSIONID=72CCDD7A91C48660B9DD01041F4BEFBB
Host: localhost:8443
Origin: https://localhost:8443
Pragma: no-cache
Referer: https://localhost:8443/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36
command: save

В регистрационния файл на конзолата няма нито грешка, нито предупреждение. Ограничението е налице и когато се използва Firefox или ако превключа HTTP сървъра от Tomcat към Jetty.

Накрая претърсих всички източници и всички буркани (включително зависимостите в местното репо на Maven) за <Unreadable>. Низът не може да бъде намерен там.

Този лимит може ли да бъде увеличен? Как да изпратите голям низ към приложение SpringBoot с помощта на метода POST? Тези отговори предполага, че практическите ограничения за POST са много по-големи от 100kB.


person scriptfoo    schedule 17.03.2021    source източник
comment
въз основа на предоставения изход, вие работите на localhost, нали? каква операционна система? Възможно ли е да имате някаква измамна антивирусна, vpn или защитна стена система, която трябва да заобиколите?   -  person eis    schedule 18.03.2021
comment
единственият инструмент, който открих, че ще изведе <unreadable>, беше gdb debugger... така че нямате никакви инструменти за отстраняване на грешки, които пречат на вашия софтуер?   -  person eis    schedule 18.03.2021
comment
Приложенията слушат на https://localhost:8443, браузърът (или Chrome, или FIrefox) е на същата локална система. Системата е Linux Mint, производна на Ubuntu 18.04. Никога не съм инсталирал антивирусна или vpn тук и дори не съм преконфигурирал iptables, но кой знае.   -  person scriptfoo    schedule 18.03.2021
comment
@eis Това е <Unreadable> т.е. започва с главна буква.   -  person scriptfoo    schedule 18.03.2021
comment
Има ли диагностични инструменти, които показват как комуникират приложенията в локална система?   -  person scriptfoo    schedule 18.03.2021
comment
@scriptfoo имате ли възможност да стартирате това приложение на друг компютър, различен от този, който използвате в момента   -  person eis    schedule 18.03.2021
comment
също така, ако натиснете /command endpoint с подобна заявка, но използвате curl или подобен инструмент, какво се случва тогава (при същия вход)   -  person eis    schedule 18.03.2021
comment
Най-лесният инструмент на @scriptfoo може просто да изпълнява netcat, така че изключете своя java сървър, направете nc -l portnumber с номера на порта, с който сте използвали вашия java сървър, натиснете заявката и наблюдавайте какво се случва   -  person eis    schedule 18.03.2021
comment
също така бихте могли да добавите към въпроса как CommandServlet всъщност получава своето съдържание, така че началото на входа за обработка на метода   -  person eis    schedule 18.03.2021
comment
Намерих нещо като MITM. Това беше дебъгерът на Netbeans, неспособен да показва низове, по-големи от въпросното ограничение. Благодаря много за помощта, това беше намек, че причината вероятно няма нищо общо с уеб програмирането. Странно е, че @eis е намерил <unreadable> в друг дебъгер. Вероятно някаква (културна) зависимост между тези две приложения.   -  person scriptfoo    schedule 18.03.2021
comment
@BalusC Не, това е нов сервлет. Тествах дали получава добри данни и добре... получи се. Аз не го направих. Да, това беше разработка на fetch, управлявана от отстраняване на грешки, защото познанията ми за Javascript са ограничени.   -  person scriptfoo    schedule 18.03.2021
comment
@scriptfoo страхотно! Моля, добавете това като отговор и го маркирайте като приет, така че този въпрос да се покаже като разрешен   -  person eis    schedule 18.03.2021
comment
@scriptfoo поне netbeans/C++ всъщност използва gdb debugger вътрешно, така че може да е същият инструмент, за който говорим, или клонинг/порт/вдъхновен от същия   -  person eis    schedule 18.03.2021


Отговори (1)


Коментаторите заподозряха, че нещо пречи. Една от подсказките беше програма за отстраняване на грешки, защото gdb използва подобно съобщение, само че не започва с главна буква. Всъщност съобщението (прикрито като реална стойност на променлива) е произведено някъде във веригата за отстраняване на грешки на Netbeans/JPDA/JVM.

person scriptfoo    schedule 18.03.2021