Запрос restTemplate к серверу Netty зависает

Ниже приведен пример RestTemplate.

public class SimpleClient {

    private final String URL;
    private AsyncRestTemplate rest = new AsyncRestTemplate(new Netty4ClientHttpRequestFactory());
    private RestTemplate restTemplate = new RestTemplate(new Netty4ClientHttpRequestFactory());

    public SimpleClient(String url) {
        this.URL = url;
        Netty4ClientHttpRequestFactory nettyFactory = new Netty4ClientHttpRequestFactory();
        try {
                    nettyFactory.setSslContext(SslContextBuilder.forClient().build());
        } catch (SSLException e) {
            e.printStackTrace();
        }
        rest = new AsyncRestTemplate(nettyFactory);
    }

    @Override
    public ResponseEntity<ResponseData> doSendByPOST(RequestData data,Class<ResponseData> clazz) {

        List<HttpMessageConverter<?>> messageConvertors = new ArrayList<>();
        messageConvertors.add(new MappingJackson2HttpMessageConverter());

        rest.setMessageConverters(messageConvertors);
        restTemplate.setMessageConverters(messageConvertors);

        HttpHeaders headers = new HttpHeaders();
        ObjectMapper objectMapper = new ObjectMapper();
        StringWriter writer = new StringWriter();
        try {
            objectMapper.writeValue(writer, data);
        } catch (IOException e) {
            e.printStackTrace();
        }
        headers.set(HttpHeaders.CONTENT_LENGTH,String.valueOf(writer.toString().getBytes(Charset.forName("UTF-8")).length));
        headers.set(HttpHeaders.CONTENT_TYPE,"application/json");
        HttpEntity<ResponseData> request = new HttpEntity<ResponseData>(headers);

        MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
        try {
            parts.add("requestData", objectMapper.writeValueAsString(data));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

//      return restTemplate.exchange(this.URL,HttpMethod.POST ,request, clazz, parts);

        ListenableFuture<ResponseEntity<ResponseData>> entity =  rest.exchange(this.URL,HttpMethod.POST ,request, clazz, parts);
        return extractResponseEntity(entity);
    }
    // ...
}

Netty читает данные из канала запроса Метод чтения

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

    if (msg instanceof HttpRequest) {
        DefaultHttpRequest defaultHttpRequest = (DefaultHttpRequest) msg;
        if (EmptyHttpHeaders.is100ContinueExpected(defaultHttpRequest)) {
            ctx.write(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.CONTINUE));
        }

        boolean keepAlive = EmptyHttpHeaders.isKeepAlive(defaultHttpRequest);


        handle = frontController.dispatchRequest(defaultHttpRequest);

    }
    if (msg instanceof HttpContent) {
        HttpContent httpContent = (HttpContent) msg;
        ByteArrayOutputStream body = new ByteArrayOutputStream(64);
        ByteBuf content = httpContent.content();
        if (content.isReadable()) {
            //body.write(content.array());
            content.readBytes(body,content.readableBytes());
            //body.append(content.toString(CharsetUtil.UTF_8));
            FullHttpResponse response = handle.handle(body);
            if(response == null){
                response = prepareDefaultResponse();
            }

            response.headers().set("content-type", "application/json");
            response.headers().set("content-length", response.content().readableBytes());
            response.headers().set("connection", HttpHeaderValues.KEEP_ALIVE);

        }

        if (msg instanceof LastHttpContent) {
            //process request
            ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
        }
    }

Приведенный ниже код работает нормально, но я предполагаю, что есть проблема с блокировкой io и неблокирующим io. Когда запрос отправлен, я не могу получить доступ к HttpContent. Я получаю только HttpRequest в качестве параметра msg. Spring resttemplate ждет ответа, но Нетти все равно :)

 if (msg instanceof HttpRequest) {
     DefaultHttpRequest defaultHttpRequest = (DefaultHttpRequest) msg;
     if (EmptyHttpHeaders.is100ContinueExpected(defaultHttpRequest)) {
         ctx.write(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.CONTINUE));
     }

     boolean keepAlive = EmptyHttpHeaders.isKeepAlive(defaultHttpRequest);


     handle = frontController.dispatchRequest(defaultHttpRequest);

 }

Моя проблема в том, как получить ответ от netty-сервера по шаблону отдыха. Я пробовал много способов выполнить полное требование / соотв. Когда restTemplate запрашивает сервер Netty, он вешает поток, поэтому я не могу перейти к реализации распределенного кеша в памяти.

Зависание в RestTemplate.java Строка: 681

Метод ждет вечно при использовании Netty4ClientHttpRequestFactory.

response = request.execute();

person Gurkan İlleez    schedule 01.01.2018    source источник
comment
Вы знаете, на какой линии он висит? Там много всего происходит, и было бы полезно получить немного больше контекста о том, что вы видите.   -  person Tristan    schedule 09.01.2018
comment
Я обновил свою проблему. Поток зависает в шаблоне покоя, потому что он ожидает, пока операция продолжит связь   -  person Gurkan İlleez    schedule 09.01.2018
comment
Вы должны указать точную строку, на которой он висит, и сократить свой код до тех частей, которые имеют отношение к делу.   -  person tkruse    schedule 10.01.2018
comment
Я думаю, что суть в том, чтобы предоставить точную информацию таким образом, чтобы другие могли отслеживать проблему. Пример полного кода может быть хорошим, так как я могу все это выложить и начать отслеживание, но также необходимо место, где он не работает / зависает. Я могу поставить там ловушку ...   -  person Michał Zaborowski    schedule 11.01.2018
comment
вы можете опубликовать свой метод extractResponseEntity?   -  person Wilder Valera    schedule 11.01.2018
comment
Он вызывается, поэтому он просто извлекает данные. entity.get (TIMEUNIT.seconds, 30) что-то вроде этого   -  person Gurkan İlleez    schedule 12.01.2018
comment
Но если вы вызовете entity.get (), вы будете блокироваться до тех пор, пока ответ не станет доступным (или пока не истекут 30 секунд) - это где ваш поток блокируется?   -  person moilejter    schedule 04.08.2018


Ответы (1)


Насколько я понимаю, вы читаете HTTP-запрос на отправку, который из Rest Client как HttpRequest Object позволяет вызывать его в первом случае, поэтому это означает, что вы даже не переходите по случаю if (msg instanceof HttpContent) {} (второй), ваш HTTP-сервер просто записывает ответ по умолчанию без какого-либо содержимого или заголовок, который вы устанавливаете во втором случае. Если это причина блокировки на стороне клиента, вы должны заполнить этот ответ по умолчанию, как и во втором случае, чтобы посмотреть, что делает клиент.

Я думаю, что netty API предоставляет этот https://netty.io/4.1/api/io/netty/handler/codec/http/DefaultFullHttpResponse.html

Также этот пример может дать вам представление о том, что может быть неправильной стороной сервера. http://www.seepingmatter.com/2016/03/30/a-simple-standalone-http-server-with-netty.html

person Alican Beydemir    schedule 04.08.2018