11

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 从请求 channelRead 方法中读取数据

@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 等待响应,但 Netty 不在乎 :)

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

 }

我的问题是如何通过 rest 模板从 netty 服务器获得响应。我尝试了很多方法来完成完整的请求/响应。当 restTemplate 请求 Netty 服务器时,它会挂起线程,所以我不能继续分布式内存缓存实现。

挂在 RestTemplate.java 行:681

使用 Netty4ClientHttpRequestFactory 时方法永远等待。

response = request.execute();
4

1 回答 1

1

据我了解,您阅读了来自 Rest Client as HttpRequestObject 的 HTTP 发布请求,让我们将其称为第一种情况,这意味着您甚至不会在这种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

于 2018-08-04T20:31:06.070 回答