У меня возникла странная проблема с обработкой метода POST в моем контроллере после включения SSL в моем приложении Spring Boot. Вот что я сделал:
- Создал самозаверяющий сертификат с помощью keytool (один на локальном хосте и один на удаленном хосте)
- Включил 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 в соответствии с указанным выше свойством.
Теперь я вижу следующее:
- На localhost
- запросы на получение работают нормально при использовании HTTPS
- запросы на отправку работают нормально при использовании HTTPS
После развертывания на другом хосте (конечно, с обновленным сертификатом)
Немного фона
Вот как выглядит мой метод:
@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).