Обработчик AWS Lambda для Spring Boot не передает ServletContextJAVA

Программисты JAVA общаются здесь
Anonymous
Обработчик AWS Lambda для Spring Boot не передает ServletContext

Сообщение Anonymous »

При запуске приложения Spring Boot на AWS Lambda я постоянно получаю сообщение об ошибке java.lang.IllegalArgumentException: ServletContext не должно быть нулевым. Я не знаю, почему это происходит, и хотел бы получить дополнительную информацию.

Вот трассировка стека:

Код: Выделить всё

2020-03-25 19:52:09.444 ERROR 8 --- [           main] c.a.s.p.internal.LambdaContainerHandler  : Error while handling request
java.lang.IllegalArgumentException:  ServletContext must not be null
at org.springframework.util.Assert.notNull(Assert.java:198) ~[spring-core-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext(WebApplicationContextUtils.java:112) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext(WebApplicationContextUtils.java:101) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at com.lukeshay.restapi.security.JwtAuthorizationFilter.doFilterInternal(JwtAuthorizationFilter.java:49) ~[task/:na]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:97) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90) ~[aws-serverless-java-container-core-1.4.jar:na]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90) ~[aws-serverless-java-container-core-1.4.jar:na]
at com.lukeshay.restapi.config.CORSConfiguration.doFilter(CORSConfiguration.java:43) ~[task/:na]
at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)  ~[aws-serverless-java-container-core-1.4.jar:na]
at com.amazonaws.serverless.proxy.internal.servlet.AwsLambdaServletContainerHandler.doFilter(AwsLambdaServletContainerHandler.java:150) ~[aws-serverless-java-container-core-1.4.jar:na]
at com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler.handleRequest(SpringBootLambdaContainerHandler.java:143) ~[aws-serverless-java-container-springboot2-1.4.jar:na]
at com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler.handleRequest(SpringBootLambdaContainerHandler.java:43) ~[aws-serverless-java-container-springboot2-1.4.jar:na]
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:211) ~[aws-serverless-java-container-core-1.4.jar:na]
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxyStream(LambdaContainerHandler.java:246) ~[aws-serverless-java-container-core-1.4.jar:na]
at com.lukeshay.restapi.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:56) ~[task/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na]
at lambdainternal.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:373) ~[aws-lambda-java-runtime-0.2.0.jar:na]
at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:897) ~[aws-lambda-java-runtime-0.2.0.jar:na]
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:228) ~[aws-lambda-java-runtime-0.2.0.jar:na]
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:162) ~[aws-lambda-java-runtime-0.2.0.jar:na]
at lambdainternal.AWSLambda.main(AWSLambda.java:157) ~[aws-lambda-java-runtime-0.2.0.jar:na]
Мой исходный код можно найти здесь: https://github.com/LukeShay/route-ratin ... switch-to- лямбда

Да, я знаю, что запускать Spring Boot на лямбде глупо, но это временно. Таким образом, мне не нужно платить за экземпляр EC2. Это также еще не доработано, поэтому я знаю, что мне следует изменить кое-что еще.

РЕДАКТИРОВАТЬ: Вот соответствующий код

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

Второй — это класс, в котором возникла ошибка, и это мой фильтр аутентификации. Я добавил комментарий // ОШИБКА ЗДЕСЬ во второй фрагмент, чтобы было легче увидеть точное место возникновения исключения.

Код: Выделить всё

package com.lukeshay.restapi;

import com.amazonaws.serverless.exceptions.ContainerInitializationException;
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
import com.amazonaws.serverless.proxy.spring.SpringBootProxyHandlerBuilder;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import com.google.common.base.Splitter;
import com.lukeshay.restapi.config.CORSConfiguration;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.Instant;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.ws.rs.core.Application;

public class StreamLambdaHandler implements RequestStreamHandler {
private static final Splitter SPLITTER = Splitter.on(',')
.trimResults()
.omitEmptyStrings();

private static SpringBootLambdaContainerHandler handler;

//  static {
//    try {
//      long startTime = Instant.now().toEpochMilli();
//
//      LambdaContainerHandler.getContainerConfig().setInitializationTimeout(20_000);
//
//      //      handler =
//      // SpringBootLambdaContainerHandler.getAwsProxyHandler(RestApiApplication.class);
//
//      handler =
//          new SpringBootProxyHandlerBuilder()
//              .defaultProxy()
//              .asyncInit(startTime)
//              .springBootApplication(RestApiApplication.class)
//              .profiles("lambda")
//              .buildAndInitialize();
//
//      // we use the onStartup method of the handler to register our custom filter
//      handler.onStartup(
//          servletContext -> {
//            FilterRegistration.Dynamic registration =
//                servletContext.addFilter("CORSConfiguration", CORSConfiguration.class);
//            registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
//          });
//    } catch (ContainerInitializationException e) {
//      e.printStackTrace();
//      throw new RuntimeException("Could not initialize Spring Boot application", e);
//    }
//  }

@Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
if (handler == null) {
try {
String listOfActiveSpringProfiles = System.getenv("SPRING_PROFILES_ACTIVE");
if (listOfActiveSpringProfiles != null) {
handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(Application.class,
splitToArray(listOfActiveSpringProfiles));
} else {
long startTime = Instant.now().toEpochMilli();

LambdaContainerHandler.getContainerConfig().setInitializationTimeout(20_000);

handler =
new SpringBootProxyHandlerBuilder()
.defaultProxy()
.asyncInit(startTime)
.springBootApplication(RestApiApplication.class)
.profiles("lambda")
.buildAndInitialize();
}
} catch (ContainerInitializationException e) {
// if we fail here.  We re-throw the exception to force another cold start
e.printStackTrace();
throw new RuntimeException("Could not initialize Spring Boot application", e);
}
}
handler.proxyStream(inputStream, outputStream, context);

outputStream.flush();
outputStream.close();
}

private static String[] splitToArray(String activeProfiles) {
return SPLITTER.splitToList(activeProfiles).toArray(new String[0]);
}
}

Код: Выделить всё

package com.lukeshay.restapi.security;

import com.lukeshay.restapi.jwt.JwtService;
import com.lukeshay.restapi.jwt.JwtServiceImpl;
import com.lukeshay.restapi.session.SessionService;
import com.lukeshay.restapi.session.SessionServiceImpl;
import com.lukeshay.restapi.user.User;
import com.lukeshay.restapi.user.UserRepository;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

private static Logger LOG = LoggerFactory.getLogger(JwtAuthorizationFilter.class.getName());

private UserRepository userRepository;
private JwtService jwtService;
private SessionService sessionService;

public JwtAuthorizationFilter(
AuthenticationManager authenticationManager, UserRepository userRepository) {
super(authenticationManager);
this.userRepository = userRepository;
}

@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {

if (jwtService == null) {
ServletContext servletContext = request.getSession().getServletContext();
WebApplicationContext webApplicationContext =
WebApplicationContextUtils.getWebApplicationContext(servletContext);  // ERROR HERE

jwtService = webApplicationContext.getBean(JwtServiceImpl.class);
sessionService = webApplicationContext.getBean(SessionServiceImpl.class);
}

String header = request.getHeader(SecurityProperties.JWT_HEADER_STRING);

if (header == null || !header.startsWith(SecurityProperties.TOKEN_PREFIX)) {
chain.doFilter(request, response);
return;
}

Authentication authentication = getUsernamePasswordAuthentication(request, response);
SecurityContextHolder.getContext().setAuthentication(authentication);

chain.doFilter(request, response);
}

private Authentication getUsernamePasswordAuthentication(
HttpServletRequest request, HttpServletResponse response) {

String jwtToken =
request
.getHeader(SecurityProperties.JWT_HEADER_STRING)
.replace(SecurityProperties.TOKEN_PREFIX, "");

if (jwtToken.trim().length() == 0) {
return null;
}

Claims jwtClaims;

try {
jwtClaims = jwtService.parseJwtToken(jwtToken);
} catch (ExpiredJwtException expiredJwtException) {

Claims refreshClaims;

try {
String refreshToken =
request
.getHeader(SecurityProperties.REFRESH_HEADER_STRING)
.replace(SecurityProperties.TOKEN_PREFIX, "");

refreshClaims = jwtService.parseJwtToken(refreshToken);
jwtClaims = expiredJwtException.getClaims();

if (refreshClaims.getId().equals(jwtClaims.getId())
&&  refreshClaims.getSubject().equals(SecurityProperties.REFRESH_HEADER_STRING)) {

String newJwtToken = jwtService.buildToken(jwtClaims);

response.addHeader(
SecurityProperties.JWT_HEADER_STRING, SecurityProperties.TOKEN_PREFIX + newJwtToken);
}
} catch (ExpiredJwtException | NullPointerException ignored) {
LOG.debug("No refresh token present or refresh token is expired.");
jwtClaims = null;
}
}

UsernamePasswordAuthenticationToken authentication = null;

if (jwtClaims != null && jwtClaims.getSubject().equals(SecurityProperties.JWT_HEADER_STRING)) {
User user = userRepository.findById(jwtClaims.getId()).orElse(null);

if (user == null) {
return null;
}

UserPrincipal principal = new UserPrincipal(user);

LOG.debug("This user token is being created.");

authentication =
new UsernamePasswordAuthenticationToken(principal, null, principal.getAuthorities());
}

return authentication;
}
}
Для получения дополнительной информации мой исходный код можно найти здесь: https://github.com/LukeShay/route-ratin ... /switch-to -лямбда


Подробнее здесь: https://stackoverflow.com/questions/608 ... letcontext

Вернуться в «JAVA»