【问题标题】:Requests and response from netty server hangs来自 netty 服务器的请求和响应挂起
【发布时间】:2015-07-15 19:38:13
【问题描述】:

我有以下代码来创建基于 netty 示例中创建的 http 服务器的 netty web 服务器。我的业务逻辑如下。

public class HttpServerHandler extends SimpleChannelInboundHandler<Object> {

    private final static Logger LOG = LogManager
        .getLogger(HttpServerHandler.class);
    private WorkflowService workflowService;
    private HttpRequest request;
    private final StringBuffer buff = new StringBuffer();
    private API avalancheApi;

    public HttpServerHandler(WorkflowService workflowService) {
        this.workflowService = workflowService;
        this.avalancheApi = new API(this.workflowService);
    }


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        LOG.debug("channelActive");
        LOG.debug(ctx.toString());
    };

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, Object msg)
        throws IOException {
        avalancheApi.setContext(ctx);
        if (msg instanceof HttpRequest) {
            HttpRequest request = this.request = (HttpRequest) msg;
            if (HttpHeaders.is100ContinueExpected(request)) {
                send100Continue(ctx);
            }
            String command = getCommand(request);
            LOG.debug(command);
            Map<String, List<String>> parameters = getParameters(request);
            LOG.debug(parameters);
            switch (command) {
            case "/login":
                ctx = avalancheApi.login(parameters);
                break;
            case "/test":
                ctx = avalancheApi.test();
                break;
            default:
                break;
            }
        }
        if (msg instanceof LastHttpContent) {
            LOG.debug("msg is of LastHttpContent");
        }
        if (!HttpHeaders.isKeepAlive(request)) {
            // If keep-alive is off, close the connection once the content is
            // fully written.
            ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(
                ChannelFutureListener.CLOSE);
        }
    }


public class API {

    private static final Logger LOG = LogManager.getLogger(API.class);
    private ChannelHandlerContext ctx;
    private HttpResponse response;
    private WorkflowService workflowService;

    public API(WorkflowService workflowService) {
        this.workflowService = workflowService;
        this.ctx = null;
    }

    public void setContext(ChannelHandlerContext ctx) {
        this.ctx = ctx;
    }

    public ChannelHandlerContext login(Map<String, List<String>> parameters)   {
        boolean success;
        String username = getUsername(parameters);
        String password = getPassword(parameters);
        User user = null;
        user = workflowService.login(username, password);
        success = validateLogin(user);
        this.response = writeLoginResponse(success);
        this.ctx.write(this.response);
        writeLoginContext(success, response);
        return this.ctx;
    }

    private void writeLoginContext(boolean success, HttpResponse response) {
        JsonObject jsonResponseMessage = new JsonObject();
        jsonResponseMessage.addProperty("result", success);
        LOG.debug(jsonResponseMessage.toString());
        this.ctx.write(Unpooled.copiedBuffer(jsonResponseMessage.toString(),
            CharsetUtil.UTF_8));

        this.response.headers().set(HttpHeaders.Names.CONTENT_LENGTH,
            jsonResponseMessage.toString().length());
    }

    private HttpResponse writeLoginResponse(boolean success) {
        if (success)
            return createSuccessfullLoginResponse();
        else
            return createLoginFailureResponse();
    }

    private HttpResponse createLoginFailureResponse() {
        return Response.loginFailureResponse();
    }

    private HttpResponse createSuccessfullLoginResponse() {
        return Response.loginSuccessResponse();
    }
}

Response 类只是创建响应和 content_type 是 application/json。内容长度在 API 类中设置。使用带有请求的python客户端,导致http://localhost/login?username=name&amp;password=pass中的请求只工作一次。第二次一切正常,但它没有完成处理请求并发送响应对象。 Api 调用正常执行,并且我还收到 LastHttpContext 消息正在打印的消息。问题有时也会发生在浏览器上。我错过了什么吗?也许内容数据和内容长度不匹配?会不会是python客户端发出请求的时候,前一个context的内容没有刷新,并且context的header的content_length值和content length不匹配?

【问题讨论】:

    标签: java netty


    【解决方案1】:

    只是猜测

    this.response.headers().set(HttpHeaders.Names.CONTENT_LENGTH,
             jsonResponseMessage.toString().length());
    

    相反,你不应该这样做jsonResponseMessage.toString().getBytes().length 吗?有时,一个字符不仅仅是一个字节。

    【讨论】:

      【解决方案2】:

      我的猜测是您已经覆盖了 API 类中的上下文,因此将响应写入了错误的上下文。您的 HttpServerHandler 是否标有 @Shareable?

      【讨论】:

      • 不,不是。您能否提供一个我希望处理程序成为@Shareable 的用例?我现在使用 FullHttpSupport 处理这个问题,并在 FullHttpSupport 对象的构造函数中传递内容。但我想它应该与 ctx.write() 一起工作对吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-18
      • 1970-01-01
      • 1970-01-01
      • 2017-05-20
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      相关资源
      最近更新 更多