vertx HttpClient使用的各种坑

茹正初
2023-12-01

vert HttpClient性能非常好,但是使用不当,就会出现非常难于定位的问题。很多问题非常严重,比如挂死,分析日志、堆栈都可能看不出任何原因。因此在写代码的时候,就需要非常注意。下面有几个排查点:

  1. 设置请求超时时间。必须合理设计超时时间,否则异常情况,会导致连接不释放。如果在response里面做其他操作,还需要重设超时时间。

    例如:

        HttpClientRequest clietRequest =

            httpClient.request(context.request().method(),

                    uri.getPort(),

                    uri.getHost(),

                    "/" + path + params).setTimeout(10000);  //设置请求超时时间

        clietRequest.handler(clientResponse -> {

            clietRequest.setTimeout(10000);  //如果解析响应还可能超时,那么也必须重设超时时间

            context.request().response().setStatusCode(clientResponse.statusCode());

            context.request().response().headers().setAll(clientResponse.headers());

            LOGGER.info("remote response begins");

            clientResponse.handler(data -> {

                context.request().response().write(data);

                LOGGER.info("remote response data transfer");

            });

            clientResponse.endHandler((v) -> {

                context.request().response().end();

                LOGGER.info("remote response data transfer end");

            });

            clientResponse.exceptionHandler(e -> {

                LOGGER.info("e", e);

            });

        });

  2. 设置闲置超时时间和最大队列大小。如果不设置,也可能导致连接不释放。新进来请求没有连接可用,造成等待挂死。需要注意的是,闲置超时时间的单位是秒,和其他接口不同。如果不看文档,肯定就弄错了。 

vertx.createHttpClient(

            new HttpClientOptions().setSsl(false)

                    .setVerifyHost(false)

                    .setTrustAll(true)

                    .setKeepAlive(true)

                    .setConnectTimeout(2000)

                    .setIdleTimeout(10)// 闲置超时时间

                    .setMaxWaitQueueSize(10)); //最大队列大小

3. 设置exceptionHandler。request和response都需要设置合理的异常处理,以跟踪错误。

        clietRequest.exceptionHandler(e -> {

            LOGGER.error("xxxxx", e);

            context.response().end();

        });

        clietRequest.connectionHandler(h -> {

            h.exceptionHandler(eh -> {

                LOGGER.error("conn", eh);

            });

            LOGGER.info("connection  " + h);

        });

 

 

在上述代码中,还有个坑

  context.request().response().headers().setAll(clientResponse.headers());

将一个请求的响应头全部拷贝到另外一个响应的头中(看起来是纯粹的HTTP转发)。这个操作是不对的。因为有些响应头是HTTP的控制消息,比如:Content-Length, Transfer-Encoding。一旦将两个头拷贝进去,就可能影响到HTTP报文的完整性(丢失或者多出额外的字节)。代码需要做一些特殊处理,不要拷贝这两个头。 

  
 类似资料: