spring-cloud-gateway
spring-cloud-gateway copied to clipboard
Gateway-Mvc FormFilter erase all parameters causing retrive parameter return null in later filter or servlet
Describe the bug Gateway-Mvc FormFilter erase all parameters causing retrive parameter return null in later filter or servlet
Sample i have a servlet for a form to post submit , but i can not retrive parameter by using request.getParameter("fool"),after i debug, i found formfilter will remove all parameters , and only offer query params to next filter or servlet
why ? , that will cause the later filter or servlet can not access any parameters.
static HttpServletRequest getRequestWithBodyFromRequestParameters(HttpServletRequest request) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
Writer writer = new OutputStreamWriter(bos, FORM_CHARSET);
Map<String, String[]> form = request.getParameterMap();
String queryString = request.getQueryString();
StringBuffer requestURL = request.getRequestURL();
if (StringUtils.hasText(queryString)) {
requestURL.append('?').append(queryString);
}
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(requestURL.toString());
//only pass queryParams for later parameters
MultiValueMap<String, String> queryParams = uriComponentsBuilder.build().getQueryParams();
for (Iterator<Map.Entry<String, String[]>> entryIterator = form.entrySet().iterator(); entryIterator
.hasNext();) {
Map.Entry<String, String[]> entry = entryIterator.next();
String name = entry.getKey();
List<String> values = Arrays.asList(entry.getValue());
for (Iterator<String> valueIterator = values.iterator(); valueIterator.hasNext();) {
String value = valueIterator.next();
List<String> queryValues = queryParams.get(name);
boolean isQueryParam = queryParams.containsKey(name) && queryValues != null
&& queryValues.contains(value);
if (!isQueryParam) {
writer.write(URLEncoder.encode(name, FORM_CHARSET));
if (value != null) {
writer.write('=');
writer.write(URLEncoder.encode(value, FORM_CHARSET));
if (valueIterator.hasNext()) {
writer.write('&');
}
}
}
}
if (entryIterator.hasNext()) {
writer.append('&');
}
}
writer.flush();
ByteArrayServletInputStream servletInputStream = new ByteArrayServletInputStream(
new ByteArrayInputStream(bos.toByteArray()));
//why only use queryParams
return new FormContentRequestWrapper(request, queryParams) {
i that we should combine the form map and queryParams to pass to RequestWrapper , i can make a PR
oh thank god I am not alone, I am hitting exactly the same issue: after incorporating spring-cloud-starter-gateway-mvc
into an existing mvc app all form post mappings (e.g. @PostMapping(value = "/mapping", params = {"save"})
) stopped working because none of the queryparams (that are given naturally as request body using form post) survive this filter.
I did not dive deeply into cloud-gateway-mvc, in my case I do path-based routing and the paths that are handled locally and the others that are proxies are completely disjunct but I guess the flexible nature of this library requires cloud-gateway-filtering of everything? Is there maybe a workaround to exclude endpoints from filtering until this issue is resolved?
Thanks in advance!
if anyone else hits this before it is fixed in here, this is my workaround (it disables the filter):
@Bean
public FormFilter formFilter() {
// see https://github.com/spring-cloud/spring-cloud-gateway/issues/3244 - this is currently a bug in spring-cloud-starter-gateway-mvc
return new FormFilter() {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
}
};
}
I stared at the code and read the comments to no avail - I do not get it, why is this Filter required? Everything is already neatly parsed as parameterMap
in the innermost request or is this just the case in my simple setup and more exotic usages (huge payloads?) require this?
This is because of the way servlet containers combine parameters. If this didn't happen, there would be duplicate request parameters.
This test fails without the filter https://github.com/spring-cloud/spring-cloud-gateway/blob/df6269ef5caf7a65657f33a17ea995b2e67a03e5/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java#L418-L436
Unfortunately, #3249 duplicates the query parameters
I'm thinking this is a documentation issue. If the custom filter is ordered before FormFilter
, you have access to request parameters before filterChain.doFilter(request, response);
. All request parameters are available after the filter chain, regardless of order.
I've added documentation as well as properties for disabling filters in #3310
I've added documentation as well as properties for disabling filters in #3310
Great. RemoveContentLengthFilter also Cause bad influence in some scenarios #3308
If those filters are good for gateway related cases, is there a way to enable them only for those gateway routes?
(Papertrail: lost another three hours trying to integrate gateway mvc as a replacement for zuul v1)
All request parameters are available after the filter chain, regardless of order.
In my case, basic spring controllers end up with no request parameters at all.