当我问这个问题时,我有点傻,因为我正在 Spring 中寻找一种方法来直接操作传入的请求,或者明确地告诉处理程序链我希望请求始终被视为 JSON。我想了一下,我意识到这正是 Servlet Filter 的用途。
首先,我创建了一个新的HttpServletRequestWrapper
看起来像这样:
public class ForcedContentTypeHttpServletRequestWrapper extends HttpServletRequestWrapper {
private static final Logger log = Logger.getLogger( ForcedContentTypeHttpServletRequestWrapper.class );
// this is the header to watch out for and what we should make sure it always resolves to.
private static final String CONTENT_TYPE_HEADER = "content-type";
private static final String CONTENT_TYPE = "application/json";
public ForcedContentTypeHttpServletRequestWrapper( HttpServletRequest request ) {
super( request );
}
/**
* If content type is explicitly queried, return our hardcoded value
*/
@Override
public String getContentType() {
log.debug( "Overriding request's content type of " + super.getContentType() );
return CONTENT_TYPE;
}
/**
* If we are being asked for the content-type header, always return JSON
*/
@Override
public String getHeader( String name ) {
if ( StringUtils.equalsIgnoreCase( name, CONTENT_TYPE_HEADER ) ) {
if ( super.getHeader( name ) == null ) {
log.debug( "Content type was not originally included in request" );
}
else {
log.debug( "Overriding original content type from request: " + super.getHeader( name ) );
}
log.debug( "Returning hard-coded content type of " + CONTENT_TYPE );
return CONTENT_TYPE;
}
return super.getHeader( name );
}
/**
* When asked for the names of headers in the request, make sure "content-type" is always
* supplied.
*/
@SuppressWarnings( { "unchecked", "rawtypes" } )
@Override
public Enumeration getHeaderNames() {
ArrayList headerNames = Collections.list( super.getHeaderNames() );
if ( headerNames.contains( CONTENT_TYPE_HEADER ) ) {
log.debug( "content type already specified in request. Returning original request headers" );
return super.getHeaderNames();
}
log.debug( "Request did not specify content type. Adding it to the list of headers" );
headerNames.add( CONTENT_TYPE_HEADER );
return Collections.enumeration( headerNames );
}
/**
* If we are being asked for the content-type header, always return JSON
*/
@SuppressWarnings( { "rawtypes", "unchecked" } )
@Override
public Enumeration getHeaders( String name ) {
if ( StringUtils.equalsIgnoreCase( CONTENT_TYPE_HEADER, name ) ) {
if ( super.getHeaders( name ) == null ) {
log.debug( "Content type was not originally included in request" );
}
else {
log.debug( "Overriding original content type from request: " + Collections.list( super.getHeaders( name ) ) );
}
log.debug( "Returning hard-coded content type of " + CONTENT_TYPE );
return Collections.enumeration( Arrays.asList( CONTENT_TYPE ) );
}
return super.getHeaders( name );
}
}
然后我将此包装器用于过滤器,如下所示:
public class ContentTypeFilter implements Filter {
/**
* @see Filter#destroy()
*/
@Override
public void destroy() {
// do nothing
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
@Override
public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException {
ForcedContentTypeHttpServletRequestWrapper requestWrapper = new ForcedContentTypeHttpServletRequestWrapper( (HttpServletRequest) request );
chain.doFilter( requestWrapper, response );
}
/**
* @see Filter#init(FilterConfig)
*/
@Override
public void init( FilterConfig fConfig ) throws ServletException {
// do nothing
}
}
它并不完全安全,但它可以正确处理来自该应用程序实际关心的单一来源的请求。