I have a class which extend Filter
class and it looks like:
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
System.out.println("--------------------------------------");
HttpServletRequest request = (HttpServletRequest) req;
req.setAttribute("test", "test");
final HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
response.setHeader("Access-Control-Max-Age", "3600");
if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
The question is can I add a custom header
to request
? I went through all method which are available inside request
and req
and couldn't find any way. But in debug
mode I found that inside CoyoteRequest
is list of headers
. How can I add there my custom header
?
You can not set the headers in HttpServletRequest
object, but you can use a wrapper class.
Look at this guide: http://wilddiary.com/adding-custom-headers-java-httpservletrequest/
Just in case for future the link becomes invalid:
final class MutableHttpServletRequest extends HttpServletRequestWrapper {
// holds custom header and value mapping
private final Map<String, String> customHeaders;
public MutableHttpServletRequest(HttpServletRequest request){
super(request);
this.customHeaders = new HashMap<String, String>();
}
public void putHeader(String name, String value){
this.customHeaders.put(name, value);
}
public String getHeader(String name) {
// check the custom headers first
String headerValue = customHeaders.get(name);
if (headerValue != null){
return headerValue;
}
// else return from into the original wrapped object
return ((HttpServletRequest) getRequest()).getHeader(name);
}
public Enumeration<String> getHeaderNames() {
// create a set of the custom header names
Set<String> set = new HashSet<String>(customHeaders.keySet());
// now add the headers from the wrapped request object
@SuppressWarnings("unchecked")
Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
while (e.hasMoreElements()) {
// add the names of the request headers into the list
String n = e.nextElement();
set.add(n);
}
// create an enumeration from the set and return
return Collections.enumeration(set);
}
}
usage:
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(req);
...
mutableRequest.putHeader("x-custom-header", "custom value");
chain.doFilter(mutableRequest, response);
}
I followed Guy Smorodinsky's answer and it worked for me but I had to add another method to the MutableHttpServletRequest:
@Override
public Enumeration<String> getHeaders(String name) {
Set<String> set = new HashSet<>();
Optional.ofNullable(customHeaders.get(name)).ifPresent(h -> set.add(h));
Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaders(name);
while (e.hasMoreElements()) {
// add the names of the request headers into the list
String n = e.nextElement();
set.add(n);
}
Optional.ofNullable(customHeaders.get(name)).ifPresent(h -> set.add(h));
return Collections.enumeration(set);
}
Guy Smorodinsky's answer is ok but for example for Spring you might want to override some additional methods, like Enumeration<String> getHeaders(String name)
, as Spring uses this while getting header value with @RequestHeader
annotation.
Example code may look something like this:
@Override
public Enumeration<String> getHeaders(String name) {
Set<String> headerValues = new HashSet<>();
headerValues.add(this.headers.get(name));
Enumeration<String> underlyingHeaderValues = ((HttpServletRequest) getRequest()).getHeaders(name);
while (underlyingHeaderValues.hasMoreElements()) {
headerValues.add(underlyingHeaderValues.nextElement());
}
return Collections.enumeration(headerValues);
}
If for any reason adding new filter or interceptor is not an option, and reflection and ugly code is OK. You can do the following to modify existing header programmatically in the controller method's body:
Warning! This is ugly and definitely shouldn't be used in production!
private void modifyHeaders(HttpServletRequest request, String headerToFind, String valueToReplace) {
Field field = request.getHeaderNames().getClass().getDeclaredField("val$names");
field.setAccessible(true);
Field field2 = field.get(request.getHeaderNames()).getClass().getDeclaredField("headers");
field2.setAccessible(true);
Field field3 = field2.get(field.get(request.getHeaderNames())).getClass().getDeclaredField("headers");
field3.setAccessible(true);
Object objects = field3.get(field2.get(field.get(request.getHeaderNames())));
List array = new ArrayList();
int length = Array.getLength(objects);
for (int i = 0; i < length; i++) {
array.add(Array.get(objects, i));
}
for (Object obj : array.toArray()) {
field = obj.getClass().getDeclaredField("nameB");
field.setAccessible(true);
Object headerKey = field.get(obj);
if (headerKey.toString().equalsIgnoreCase(headerToFind)) {
field = obj.getClass().getDeclaredField("valueB");
field.setAccessible(true);
MessageBytes messageBytes = MessageBytes.newInstance();
messageBytes.setString(valueToReplace));
field.set(obj, messageBytes);
break;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With