Мы отправляем данные в двоичном кодированном виде в качестве полезной нагрузки запроса JSON в наш сервер Netty. На небольших полезных нагрузках (1-2 МБ) все в порядке, но на больших полезных нагрузках происходит сбой с HTTP 413 Request entity too large
.
Мы нашли два места, где это может быть затронуто:
- конструктор для HttpObjectAggregator
- конструктор для анализатора тела JsonObjectDecoder .
Мы установили первое значение по умолчанию выше (10 МБ) нашего порогового значения проблемы (5 МБ), а второе мы вообще не используем, поэтому мы не уверены, как в этом разобраться.
(Кстати, мы намерены не использовать JSON для больших двоичных полезных нагрузок в будущем, поэтому «полезные» советы по изменению базовой архитектуры не требуются ;-))
Настройка трубопровода
У нас есть два этапа инициализации конвейера, где первый этап зависит от того, является ли комбинация версии протокола HTTP и SSL, а последний этап касается только обработчиков уровня приложения. PipelineInitializer
это просто внутренний интерфейс.
/**
* This class is concerned with setting up the handlers for the protocol level of the pipeline
* Only use it for the cases where you know the passed in traffic will be HTTP 1.1
*/
public class Http1_1PipelineInitializer implements PipelineInitializer {
private final static int MAX_CONTENT_LENGTH = 10 * 1024 * 1024; // 10MB
@Override
public void addHandlersToPipeline(ChannelPipeline pipeline) {
pipeline.addLast(
new HttpServerCodec(),
new HttpObjectAggregator(MAX_CONTENT_LENGTH),
new HttpChunkContentCompressor(),
new ChunkedWriteHandler()
);
}
}
Настройка конвейера уровня приложения в нашем ApplicationPipelineInitializer. Я не думаю, что они так актуальны, но включены для полноты. Все обработчики в этой части являются определяемыми пользователем обработчиками:
@Override
public void addHandlersToPipeline(final ChannelPipeline pipeline) {
pipeline.addLast(
new HttpLoggerHandler(),
userRoleProvisioningHandler,
authHandlerFactory.get(),
new AuthenticatedUserHandler(services),
createRoleHandlerFactory(configuration, services, externalAuthorizer).get(),
buildInfoHandler,
eventStreamEncoder,
eventStreamDecoder,
eventStreamHandler,
methodEncoder,
methodDecoder,
methodHandler,
fileServer,
notFoundHandler,
createInterruptOnErrorHandler());
// Prepend the error handler to every entry in the pipeline. The intention behind this is to have a catch-all
// outbound error handler and thereby avoiding the need to attach a listener to every ctx.write(...).
final OutboundErrorHandler outboundErrorHandler = new OutboundErrorHandler();
for (Map.Entry<String, ChannelHandler> entry : pipeline) {
pipeline.addBefore(entry.getKey(), entry.getKey() + "#OutboundErrorHandler", outboundErrorHandler);
}
}
Netty версия 4.1.15