简体   繁体   中英

Requests and response from netty server hangs

I have the following code to create a netty web server based on http server created in the netty's example. My buisness logic is the following.

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 class is only creating the response and the content_type which is of application/json. Content Length is set in the API class. Using python client with requests, results in the request made in http://localhost/login?username=name&password=pass works only once. The second time everything works, but it doesn't finish processing the request and send the response object. Api calls get executed normally, and I also get the message of LastHttpContext message getting print. The problem sometimes happens with browser too. Am I missing something? Maybe the content data and the content length doesn't match? Could it be that when making requests from python client, the content of the previous context isn't flushed and the content_length value of the header and content length of the context doesn't match?

Just wild guess

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

Instead, shouldn't you be doing jsonResponseMessage.toString().getBytes().length ?? Sometimes, one character is not just one byte.

My guess is that you have overwritten the context in your API class, and as a result, are writing the response to the wrong context. Is your HttpServerHandler marked with @Shareable?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM