GH-3283: HTTP Inbound handle SpEL errors (#3289)

* GH-3283: HTTP Inbound handle SpEL errors

Fixes https://github.com/spring-projects/spring-integration/issues/3283

* Process all the request message preparation exceptions
in the provided error channel to let target application
to make a decision about an appropriate HTTP status instead of
default 500 Server Error

* * Rephrase `ResponseStatusException` doc in the http.adoc

Co-authored-by: Gary Russell <grussell@vmware.com>

Co-authored-by: Gary Russell <grussell@vmware.com>
This commit is contained in:
Artem Bilan
2020-05-28 11:47:15 -04:00
committed by GitHub
parent 5bd6278fcb
commit ef939a09a4
3 changed files with 67 additions and 17 deletions

View File

@@ -59,8 +59,10 @@ import org.springframework.integration.http.multipart.MultipartHttpInputMessage;
import org.springframework.integration.support.AbstractIntegrationMessageBuilder;
import org.springframework.integration.support.json.JacksonPresent;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.converter.MessageConversionException;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
@@ -267,30 +269,46 @@ public abstract class HttpRequestHandlingEndpointSupport extends BaseHttpInbound
Map<String, Object> headers = getHeaderMapper().toHeaders(httpEntity.getHeaders());
Object payload = null;
if (getPayloadExpression() != null) {
// create payload based on SpEL
payload = getPayloadExpression().getValue(evaluationContext);
}
Message<?> message = null;
try {
if (getPayloadExpression() != null) {
// create payload based on SpEL
payload = getPayloadExpression().getValue(evaluationContext);
}
if (!CollectionUtils.isEmpty(getHeaderExpressions())) {
headers.putAll(
ExpressionEvalMap.from(getHeaderExpressions())
.usingEvaluationContext(evaluationContext)
.withRoot(httpEntity)
.build());
}
if (!CollectionUtils.isEmpty(getHeaderExpressions())) {
headers.putAll(
ExpressionEvalMap.from(getHeaderExpressions())
.usingEvaluationContext(evaluationContext)
.withRoot(httpEntity)
.build());
}
if (payload == null) {
if (httpEntity.getBody() != null) {
payload = httpEntity.getBody();
if (payload == null) {
if (httpEntity.getBody() != null) {
payload = httpEntity.getBody();
}
else {
payload = requestParams;
}
}
message = prepareRequestMessage(servletRequest, httpEntity, headers, payload);
}
catch (Exception ex) {
MessageConversionException conversionException =
new MessageConversionException("Cannot create request message", ex);
MessageChannel errorChannel = getErrorChannel();
if (errorChannel != null) {
this.messagingTemplate.send(errorChannel,
buildErrorMessage(null,
conversionException));
}
else {
payload = requestParams;
throw conversionException;
}
}
Message<?> message = prepareRequestMessage(servletRequest, httpEntity, headers, payload);
Message<?> reply = null;
if (isExpectReply()) {
try {

View File

@@ -40,6 +40,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestFactory;
@@ -56,6 +57,7 @@ import org.springframework.integration.security.channel.SecuredChannel;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.ErrorMessage;
import org.springframework.mock.web.MockPart;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.vote.AffirmativeBased;
@@ -81,6 +83,7 @@ import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.DispatcherServlet;
/**
@@ -235,6 +238,30 @@ public class HttpDslTests {
flowRegistration.destroy();
}
@Test
public void testBadRequest() throws Exception {
IntegrationFlow flow =
IntegrationFlows.from(
Http.inboundGateway("/badRequest")
.errorChannel((message, timeout) -> {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"Not valid request param", ((ErrorMessage) message).getPayload());
})
.payloadExpression("#requestParams.p1"))
.get();
IntegrationFlowContext.IntegrationFlowRegistration flowRegistration =
this.integrationFlowContext.registration(flow).register();
this.mockMvc.perform(
get("/badRequest")
.with(httpBasic("user", "user"))
.param("p2", "P2"))
.andExpect(status().isBadRequest())
.andExpect(status().reason("Not valid request param"));
flowRegistration.destroy();
}
@Configuration
@EnableWebSecurity