Странное поведение обработчика POST в Spring Boot после включения SSL - PullRequest
0 голосов
/ 29 мая 2020

У меня возникла странная проблема с обработкой метода POST в моем контроллере после включения SSL в моем приложении Spring Boot. Вот что я сделал:

  1. Создал самозаверяющий сертификат с помощью keytool (один на локальном хосте и один на удаленном хосте)
  2. Включил SSL в application.properties, например:
server.port=8444
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:keystore/cert.p12
server.ssl.key-store-password=somepwd
server.ssl.key-alias=cert
Поместил cert.p12 в соответствии с указанным выше свойством.

Теперь я вижу следующее:

  1. На localhost
  • запросы на получение работают нормально при использовании HTTPS
  • запросы на отправку работают нормально при использовании HTTPS
После развертывания на другом хосте (конечно, с обновленным сертификатом)
  • запросы на получение работают нормально при использовании HTTPS

  • почтовые запросы не работают при использовании HTTPS и возвращают следующее сообщение:

    Решено [org.springframework.http.converter.HttpMessageNotReadableException: отсутствует требуемое тело запроса: publi c org.springframework.http.ResponseEntity com.app.updateData (java .lang.String)]

Немного фона

Вот как выглядит мой метод:

@CrossOrigin(origins = "*") 
@PostMapping(path="/api/data-update")
public ResponseEntity<String> updateData(@RequestBody String data) {...}

Я тестирую его следующим образом (используя curl).

На localhost ( который отлично работает):

curl -k -X POST -H "Content-Type: application/json" -H "Content-Encoding: gzip" --data-binary @./test_data.gzip https://localhost:8444/api/data-update

На удаленном сервере (который возвращает ошибку, указанную выше):

curl -k -X POST -H "Content-Type: application/json" -H "Content-Encoding: gzip" --data-binary @./test_data.gzip https://remoteserver:8444/api/data-update

Итак, в основном то, что я делаю, - это отправлять через POST заархивированный JSON файл. Обратите внимание, что этот метод отлично работает, когда я отключаю конфигурацию SSL (что означает, что я использую HTTP), а также когда я тестирую его на локальном хосте. Он перестает работать только при попытке выполнить приведенный выше curl на внешнем сервере.

Надеюсь, я предоставил все подробности, которые могут понадобиться кому-то, чтобы предложить возможное решение этой проблемы.

Заранее большое спасибо!

ОБНОВЛЕНИЕ:

Первоначально я думал, что не могу быть из-за включенного мною фильтра для обработки файла GZIP, но он оказывается из того, что описанная выше проблема возникает только для двоичных данных, которые я пытаюсь выполнить с помощью POST с помощью curl. Если я отправляю текст JSON данных другому контроллеру, он работает нормально. Я не думаю, что это сам фильтр, потому что другие фильтры работают, так что мой главный подозреваемый - это извлечение GZIP, но я не могу найти в нем ничего плохого.

Вот мой класс фильтра:

package com.app.filter;

import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.zip.GZIPInputStream;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;

@Component
public class GzipBodyDecompressFilter implements Filter {

    private static final Logger logger = LogManager.getLogger(GzipBodyDecompressFilter.class);

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;

        String encoding = request.getHeader("Content-Encoding");
        if (encoding != null && encoding.equals("gzip")) {
            logger.info("GZIP extraction");
            request = new GzippedInputStreamWrapper((HttpServletRequest) servletRequest);
        }

        chain.doFilter(request, servletResponse);
    }

    final class GzippedInputStreamWrapper extends HttpServletRequestWrapper {

        public static final String DEFAULT_ENCODING = "ISO-8859-1";
        private byte[] bytes;

        public GzippedInputStreamWrapper(final HttpServletRequest request) throws IOException {
            super(request);

            try {
                final InputStream in = new GZIPInputStream(request.getInputStream());
                bytes = IOUtils.toByteArray(in);
            } catch (EOFException e) {
                bytes = new byte[0];
            }
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            final ByteArrayInputStream sourceStream = new ByteArrayInputStream(bytes);

            return new ServletInputStream() {
                public int read() throws IOException {
                    return sourceStream.read();
                }

                @Override
                public void setReadListener(ReadListener listener) {
                    // TODO Auto-generated method stub

                }

                @Override
                public boolean isFinished() {
                    // TODO Auto-generated method stub
                    return false;
                }

                @Override
                public boolean isReady() {
                    // TODO Auto-generated method stub
                    return false;
                }

                public void close() throws IOException {
                    super.close();
                    sourceStream.close();
                }
            };
        }

        @Override
        public Map getParameterMap() {
            return super.getParameterMap();
        }
    }
}

ОБНОВЛЕНИЕ 2:

Просто случайно я попытался отправить другой JSON файл, который намного меньше (~ 1,2 КБ), и он сработал. Значит, в настройках Tomcat должно быть что-то, что блокирует запросы, но я ничего не могу найти (опять же, он отлично работает для HTTP, только отклоняет большие запросы HTTPS).

1 Ответ

0 голосов
/ 25 августа 2020

Я не нашел встроенной настройки Tomcat, которая позволила бы мне отправить более крупный запрос. Итак, моим единственным решением на этот день было изменить конфигурацию Spring Boot, чтобы она запускала приложение на встроенном веб-сервере Jetty вместо Tomcat. Судя по всему, Jetty принимает такие запросы по умолчанию и работает из коробки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...