Тело HttpServletRequest пусто, когда война развернута в AWS

Я вижу несоответствие в поведении моего кода при работе на моей локальной машине по сравнению с AWS Elastic Beanstalk. Код для получения уведомления от Google Glass.

Фрагмент кода выглядит следующим образом:

public class NotifyServlet extends HttpServlet implements WeiboConstants{
    private static final Logger LOG = Logger.getLogger(NotifyServlet.class.getSimpleName());

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        // Respond with OK and status 200 in a timely fashion to prevent redelivery
        response.setContentType("text/html");
        Writer writer = response.getWriter();
        writer.append("OK");
        writer.close();

        LOG.info("perpare reading");

        BufferedReader notificationReader =
            new BufferedReader(new InputStreamReader(request.getInputStream()));
        String notificationString = "";

        LOG.info("begin reading ");
        // Count the lines as a very basic way to prevent Denial of Service attacks
        int lines = 0;
        while (notificationReader.ready()) {
            LOG.info("reading");
            notificationString += notificationReader.readLine();
            lines++;

            // No notification would ever be this long. Something is very wrong.
            if (lines > 1000) {
                throw new IOException("Attempted to parse notification payload that was unexpectedly long.");
            }
        }

        LOG.info("got raw notification " + notificationString);

        JsonFactory jsonFactory = new JacksonFactory();

Сервер Google будет делать POST, который регистрируется отдельно:

Subscription subscription = MirrorClient.insertSubscription(credential, "https://mirrornotifications.appspot.com/forward?url=http://foo.elasticbeanstalk.com/notify", userId,
                        "timeline");

При тестировании на моей локальной машине я запускал mvn jetty: запустить и изменить foo в приведенном выше коде my ip address:8080,

Я могу получить уведомление от Google:

{"collection": "timeline", "itemId": "5cbf8f54-822d-4a8e-9a9f-508687bbb9e2", "operation": "INSERT", "userToken": "105242333117256730066", "userActions": [{"type": "LAUNCH"}]}

Но когда я упаковал войну (mvn war:war) и развернул ее в AWS, из журнала я вижу, что она была успешно зарегистрирована в Google, и я получаю POST от Google на / уведомить, но похоже на тело пусто, как показано в следующем журнале:

Dec 06, 2013 5:01:55 AM com.google.glassware.NotifyServlet doPost
INFO: perpare reading
Dec 06, 2013 5:01:55 AM com.google.glassware.NotifyServlet doPost
INFO: begin reading 
Dec 06, 2013 5:01:55 AM com.google.glassware.NotifyServlet doPost
INFO: got raw notification 
Dec 06, 2013 5:01:55 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [notify] in context with path [] threw exception
java.lang.IllegalArgumentException: no JSON input found

Как я могу отлаживать дальше?

ОБНОВИТЬ

Я развернул тот же файл war на сервере под управлением Jetty вместо Tomcat, и он работает нормально, кажется, что это особая проблема Tomcat?

1 ответ

Для дальнейшей отладки вы можете попытаться опубликовать уведомление прямо на http://foo.elasticbeanstalk.com/notify

Если это приводит к тому же поведению, я бы поближе BufferedReader.ready() как условие цикла.

ready() это неблокирующий метод. Это означает, что если по какой-то причине BufferedReader не готов немедленно вернуть данные, тогда метод немедленно вернет false, и цикл будет полностью пропущен.

Тогда следующим шагом в отладке будет закомментировать ready() и идти прямо с блокировкой readLine() чтобы подтвердить, что ваш сервлет получает полезную нагрузку.

Обновить

Кажется, что у Jetty и Tomcat есть разные реализации для BufferedReader.ready().

Вот связанный вопрос переполнения стека, который я нашел после дальнейших исследований: BufferedReader ready method

Другие вопросы по тегам