CXF буфериране на данни при използване на кодиране на парчета

Написах java REST (поточно предаване) сървлет с помощта на Apache CXF 2.5.1 и го внедрих в контейнер Tomcat 7.0.42. Крайната точка REST по същество е имплементация на StreamingOutput го обви в Response обект, който се предава на контейнера, когато клиент поиска.

Естеството на услугата е да върне поток от сензорни данни на клиент. Този поток теоретично може да бъде безкрайно дълъг, защото се прекратява само когато клиентът прекъсне връзката. Проблемът възниква, когато данните, генерирани от сензора, идват в малки количества.

Услугата „работи“, но се натъквам на проблем, когато става въпрос за размера на отговорите на данните, които клиентът получава. Клиентът получава данни само след като прагът от 8192 байта е надхвърлен от услугата. След това клиентът получава 800 байта, след това 8192 байта, след това 800 байта...

Бих искал данните да бъдат изпратени на клиента веднага щом извикам flush на OutputStream, който контейнерът предава на моята реализация на StreamingOutput. Въпреки това, изпълнението на OutputStream, което ми е дадено (WrappedOutputStream, дефинирано в org.apache.cxf.transport.http.AbstractHTTPDestination) има метод за промиване, който не прави нищо.

Има ли някакъв начин да имам повече контрол върху OutputStream, който CXF използва, за да мога да „промивам“ към клиента при поискване?


person harumph    schedule 18.12.2013    source източник


Отговори (3)


В крайна сметка начинът, по който успях да изчистя буфера при поискване, беше да създам CXF филтър, по-специално реализация на ResponseHandler.

Във филтъра хванах HttpServletResponse и Реализация на OutputStream, която CXF използва (тази, която не ми позволи да изчистя) от имплементацията на съобщението, обгръщайки ги във FilteredOutputStream. Всеки път, когато се извиква flush, аз изрично извиквам flush на HttpServletResponse.

Това е специфично за CXF и правенето му по този начин може да създаде много повече излишни разходи, в зависимост от това колко често се извиква флъш, но позволява "бавното" поточно предаване да достигне до клиента по-рано.

Моля, коментирайте всякакви проблеми или неща, за които може да се наложи да се притеснявам.

person harumph    schedule 20.12.2013
comment
Хубава находка! Трябва да създадете дефект и да предоставите корекцията си на общността на CXF, за да видите как ще реагират. issues.apache.org/jira/browse/CXF - person Raphael Jolivet; 31.10.2014

Има две неща, които ще искате да проверите. Първо, вероятно ще трябва да зададете заглавка Content-Length (response.setHeader()), второ, може да се наложи да зададете размера на буфера (response.setBufferSize()). Тук изглежда има дискусия по този въпрос:

Как да деактивирате Transfer-Encoding в Tomcat 6

person Zeki    schedule 18.12.2013
comment
Нито setHeader, нито setBufferSize са в договора за Response. Също така не се опитвам да деактивирам нарязването. Как би ми помогнало деактивирането му? Почти съм сигурен, че искам групиране, просто бих искал CXF да използва OutputStream, който зачита моето извикване на flush(). - person harumph; 19.12.2013
comment
Хм.. Не съм сигурен, че можете да имате chunking и също така да наложите флъш през целия път. - person Zeki; 19.12.2013

Самият Tomcat трябва да ангажира отговора веднага щом извършите flush(). Това може да е проблем с CXF.

Ако сте готови за предложение, може да ви препоръчам да преминете към използване на websocket за този вид приложение: това е много по-подходящо за дългосрочно поточно предаване на данни от сървър към клиент (или дори обратното). Ако не харесвате WebSocket, трябва поне да погледнете асинхронния I/O със спецификация на Servlet 3.0 или дори Comet (въпреки че 3.0-async е по-добър избор IMO за поддръжка и т.н.).

person Christopher Schultz    schedule 18.12.2013