Jetty莫名其妙地吃了POST参数

时间:2013-12-18 19:58:56

标签: jetty embedded-jetty

我正在运行嵌入式Jetty(9.1.0.v20131115)设置,并且有几个处理程序设置来处理几个不同上下文的请求。

当用户提交表单时,其中一个处理程序会执行登录功能。它的设置如下:

ContextHandler loginContext = new ContextHandler("/login");
loginContext.setHandler(new LoginHandler());

// Other handlers go here...

contexts.setHandlers(new Handler[]{rootContext, logoutContext, loginContext, resourceHandler});
server.setHandler(contexts);

那应该是非常标准的,没什么特别的。令我困惑的是,当我通过调试器运行LoginHandler时,HttpServletRequest对象没有参数,即使表单显然有两个表单输入元素!

这是我通过netcat捕获的请求的副本:

POST /login HTTP/1.1
Host: localhost:52520
Connection: keep-alive
Content-Length: 31
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://localhost:52520
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://localhost:52520/dashboard/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8

username=myuser&password=mypass

最重要的是,如果我将表单操作更改为GET而不是POST,则参数显示就好了!

为了让Handler接受POST参数,还有什么特别之处吗?

1 个答案:

答案 0 :(得分:2)

似乎工作正常。

package jetty;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.InetSocketAddress;
import java.net.Socket;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.util.IO;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class JettyPostTest
{
    public static class LoginHandler extends HandlerWrapper
    {
        @Override
        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
        {
            PrintWriter out = response.getWriter();
            response.setContentType("text/plain");

            out.printf("username = %s\n",request.getParameter("username"));
            out.printf("password = %s\n",request.getParameter("password"));

            baseRequest.setHandled(true);
        }
    }

    private static Server server;
    private static int port;

    @BeforeClass
    public static void startServer() throws Exception
    {
        server = new Server();
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(0);
        server.addConnector(connector);

        // collection for handlers
        HandlerCollection handlers = new HandlerCollection();
        server.setHandler(handlers);

        // login context
        ContextHandler loginContext = new ContextHandler("/login");
        loginContext.setHandler(new LoginHandler());
        handlers.addHandler(loginContext);

        // default handler
        handlers.addHandler(new DefaultHandler());

        // start server
        server.start();

        // grab port
        port = connector.getLocalPort();
    }

    @AfterClass
    public static void stopServer() throws Exception
    {
        server.stop();
    }

    @Test
    public void testPostParameters() throws IOException
    {
        StringBuilder req = new StringBuilder();
        req.append("POST /login/ HTTP/1.1\r\n");
        req.append("Host: localhost:").append(port).append("\r\n");
        req.append("Connection: close\r\n");
        req.append("Content-Length: 31\r\n");
        req.append("Cache-Control: max-age=0\r\n");
        req.append("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n");
        req.append("Origin: http://localhost:").append(port).append("\r\n");
        req.append("User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36\r\n");
        req.append("Content-Type: application/x-www-form-urlencoded\r\n");
        req.append("Referer: http://localhost:").append(port).append("/dashboard/\r\n");
        req.append("Accept-Encoding: gzip,deflate,sdch\r\n");
        req.append("Accept-Language: en-US,en;q=0.8\r\n");
        req.append("\r\n");
        req.append("username=myuser&password=mypass\r\n");

        try (Socket socket = new Socket())
        {
            socket.connect(new InetSocketAddress("localhost",port));
            // Write request
            try (OutputStream out = socket.getOutputStream();
                    OutputStreamWriter writer = new OutputStreamWriter(out);
                    InputStream in = socket.getInputStream();
                    InputStreamReader reader = new InputStreamReader(in))
            {
                StringReader reqStream = new StringReader(req.toString());
                IO.copy(reqStream,writer);
                writer.flush();
                out.flush();

                StringWriter respStream = new StringWriter();
                IO.copy(reader,respStream);

                System.out.println(respStream.toString());

                String expected = "username = myuser\npassword = mypass\n";
                assertThat("Response",respStream.toString(),containsString(expected));
            }
        }
    }
}

输出结果:

2013-12-18 13:23:08.856:INFO:oejs.Server:main: jetty-9.1.0.v20131115
2013-12-18 13:23:08.888:INFO:oejsh.ContextHandler:main: Started o.e.j.s.h.ContextHandler@49ada86{/login,null,AVAILABLE}
2013-12-18 13:23:08.897:INFO:oejs.ServerConnector:main: Started ServerConnector@3f14b553{HTTP/1.1}{0.0.0.0:34456}
HTTP/1.1 200 OK
Content-Type: text/plain; charset=ISO-8859-1
Connection: close
Server: Jetty(9.1.0.v20131115)

username = myuser
password = mypass

2013-12-18 13:23:08.994:INFO:oejs.ServerConnector:main: Stopped ServerConnector@3f14b553{HTTP/1.1}{0.0.0.0:0}
2013-12-18 13:23:08.995:INFO:oejsh.ContextHandler:main: Stopped o.e.j.s.h.ContextHandler@49ada86{/login,null,UNAVAILABLE}

只有我对您的请求所做的更改才是将Connection: keep-alive更改为Connection: close,让jetty关闭连接。此更改很小,仅允许测试快速执行,使用原始值不会更改测试结果。

您的问题中缺少某些信息。