当前位置: 首页 > 知识库问答 >
问题:

使用Netty HTTP客户端重试请求

桓瀚
2023-03-14

如何在基于网络的 HTTP 客户端中重试 HTTP 请求?

请考虑以下处理程序,如果收到 HTTP 响应代码 503,它将尝试在 1 秒后重试 HTTP 请求:

public class RetryChannelHandler extends ChannelDuplexHandler {
    List<HttpObject> requestParts;

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        if (msg instanceof HttpRequest) {
            requestParts = new ArrayList<>();
            requestParts.add((HttpRequest)msg);
        } else if (msg instanceof HttpObject) {
            requestParts.add((HttpObject)msg);
        }

        super.write(ctx, msg, promise);
    }

    @Override
    public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof HttpResponse) {
            HttpResponse res = (HttpResponse)msg;
            if (res.status().code() == 503) {
                ctx.executor().schedule(new Runnable() {
                    @Override
                    public void run() {
                        for (HttpObject obj : requestParts) {
                            ctx.channel().write(obj);
                        }
                    }
                }, 1000, TimeUnit.MILLISECONDS);
            } else {
                super.channelRead(ctx, msg);
            }
        } else {
            super.channelRead(ctx, msg);
        }
    }
}

在本例中,当我写入通道时,管道中的其他处理程序会看到HttpObjects,但实际上不会再次执行HttpRequest——只接收到一个HttpResponse。

我认为在这种情况下我只是滥用了 Channel,我需要创建一个新的通道(表示与服务器的新连接)来执行重试。我不清楚的是,如何从处理程序的上下文中创建新的通道,以及我是否真的处于Netty的正确层来执行这种逻辑。

如能就如何实现我所描述的行为提供任何指导,我们将不胜感激。

共有1个答案

冯奇思
2023-03-14

您还需要在调用write(…)之后调用 flush(),否则它将不会刷新通道。此外,您还需要确保您可能保留()并复制() HttpContent,否则您可能会尝试编写一个已经发布的 HttpContentobject。

类似这样(未测试):

public class RetryChannelHandler extends ChannelDuplexHandler {
    Queue<HttpObject> requestParts;

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        if (msg instanceof HttpRequest) {
            requestParts = new ArrayDeque<>();
            requestParts.add((HttpRequest)msg);
        } else if (msg instanceof HttpContent) {
            requestParts.add(((HttpContent)msg).duplicate().retain());
        }

        super.write(ctx, msg, promise);
    }

    @Override
    public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof HttpResponse) {
            HttpResponse res = (HttpResponse)msg;
            if (res.status().code() == 503) {
                ctx.executor().schedule(new Runnable() {
                    @Override
                    public void run() {
                        HttpObject obj;
                        while ((obj = requestParts.poll()) != null) {
                            ctx.write(obj);
                        }
                        ctx.flush();
                    }
                }, 1000, TimeUnit.MILLISECONDS);
            } else {
                HttpObject obj;
                while ((obj = requestParts.poll()) != null) {
                    ReferenceCountUtil.release(obj);
                }
                super.channelRead(ctx, msg);
            }
        } else {
            super.channelRead(ctx, msg);
        }
    }
}
 类似资料:
  • 测试: 现在我得到了这个错误:

  • 客户端的HTTP/HTTPS请求。 进程:主进程​ ClientRequest是由EventEmitter来实现Writable Stream​ new ClientRequest(options) 作用:发起新的HTTP/HTTPS请求 options(Object | String) - options是String时即请求URL。 options 是Object时则按以下属性请求: meth

  • 我是WebClient字段的新手,但我遇到了以下问题。这是我的客户端方法,您已经看到它应该插入我发送到数据库参数的值,但我无法插入它。 我在这里写的代码是我的控制器区域。 当我运行我的方法时,我无法将值添加到服务器端的数据库中,但我可以使用以下使用客户端方法的方法从那里获取值。

  • httplib 库主要用来模拟客户端发送 HTTP 请求,类似于 Curl 工具,支持 JQuery 类似的链式操作。使用起来相当的方便;通过如下方式进行安装: go get github.com/astaxie/beego/httplib 如何使用 首先导入包 import ( "github.com/astaxie/beego/httplib" ) 然后初始化请求方法,返回对象 r

  • 当浏览器请求一个网页时,它会向网络服务器发送一系列不能被直接读取的信息,因为这些信息是作为HTTP信息头的一部分来传送的。您可以查阅HTTP协议来获得更多的信息。 下表列出了浏览器端信息头的一些重要内容,在以后的网络编程中将会经常见到这些信息: 信息 描述 Accept 指定浏览器或其他客户端可以处理的MIME类型。它的值通常为 image/png 或 image/jpeg Accept-Char

  • 1. 创建 Maven 工程 服务端部署完毕后,我们可以新建一个 Maven 工程使用 SOFARegistry 提供的服务。首先新建一个 Maven 工程,然后引入如下依赖: <dependency> <groupId>com.alipay.sofa</groupId> <artifactId>registry-client-all</artifactId> <versi