我正在尝试实现这个Jsonp Filter。
但是,每当我调用我的 url/server/api.jsonp?callback=something
时,它都会削减响应的最后一部分(ContentLength 具有原始响应输出的长度。在这种情况下,这将是 15,因为这{test: 'blaat'}
是我的原始响应输出 - 请参阅控制器)。
至少这是我的假设,因为我得到的输出是test({test: 'bl
. 有人知道如何让过滤器工作并发送正确的响应吗?(我什至尝试强制 Content-length - 请参阅 JsonpCallbackFilter)
筛选:
public class JsonpCallbackFilter implements Filter {
protected final Log logger = LogFactory.getLog(JsonpCallbackFilter.class);
@Override
public void init(FilterConfig fConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
Map<String, String[]> params = httpRequest.getParameterMap();
if (params.containsKey("callback")) {
if (logger.isDebugEnabled()) {
logger.debug("Wrapping response with JSONP callback: " + params.get("callback")[0]);
}
OutputStream out = httpResponse.getOutputStream();
GenericResponseWrapper wrapper = new GenericResponseWrapper(httpResponse);
chain.doFilter(request, wrapper);
byte[] callBack = (params.get("callback")[0] + "(").getBytes();
byte[] callBackEnd = (");").getBytes();
byte[] jsonpResponse = new byte[callBack.length + wrapper.getData().length + callBackEnd.length];
System.arraycopy(callBack, 0, jsonpResponse, 0, callBack.length);
System.arraycopy(wrapper.getData(), 0, jsonpResponse, callBack.length, wrapper.getData().length);
System.arraycopy(callBackEnd, 0, jsonpResponse, callBack.length + wrapper.getData().length, callBackEnd.length);
logger.debug(new String(jsonpResponse));
logger.debug("Length: " + jsonpResponse.length);
out.write(jsonpResponse);
wrapper.setContentType("text/javascript;charset=UTF-8");
wrapper.setContentLength(jsonpResponse.length);
} else {
if (logger.isDebugEnabled()) {
logger.debug("No callback found, resort to default json request!");
}
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}
通用响应包装器:
public class GenericResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream output;
private FilterServletOutputStream filterStream;
private PrintWriter printWriter;
private int contentLength;
private String contentType;
public GenericResponseWrapper(HttpServletResponse response) {
super(response);
output = new ByteArrayOutputStream();
filterStream = new FilterServletOutputStream(output);
printWriter = new PrintWriter(output, true);
}
public byte[] getData() {
printWriter.close();
return output.toByteArray();
}
@Override
public ServletOutputStream getOutputStream() {
return filterStream;
}
@Override
public PrintWriter getWriter() {
return printWriter;
}
public int getContentLength() {
return contentLength;
}
@Override
public void setContentLength(int length) {
this.contentLength = length;
super.setContentLength(length);
}
@Override
public String getContentType() {
return contentType;
}
@Override
public void setContentType(String contentType) {
this.contentType = contentType;
super.setContentType(contentType);
}
}
自定义过滤器输出流:
public class FilterServletOutputStream extends ServletOutputStream {
private DataOutputStream stream;
public FilterServletOutputStream(OutputStream output) {
stream = new DataOutputStream(output);
}
@Override
public void write(int b) throws IOException {
stream.write(b);
}
@Override
public void write(byte[] b) throws IOException {
stream.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
stream.write(b, off, len);
}
}
web.xml 过滤器映射:
<filter>
<filter-name>jsonpCallbackFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>jsonpCallbackFilter</filter-name>
<url-pattern>*.jsonp</url-pattern>
</filter-mapping>
applicationContext.xml 中的 bean 映射
<bean id="jsonpCallbackFilter" class="com.world2.utils.spring.filters.jsonp.JsonpCallbackFilter" />
控制器:
@Controller
public class ApiRequests {
protected final Logger logger = Logger.getLogger(ApiRequests.class);
@RequestMapping(value = "api.json", produces = {"application/json"}, method = RequestMethod.GET)
@ResponseBody
public String handleActionJson(final HttpServletRequest request){
return "{test: 'blaat'}";
}
@RequestMapping(value = "api.jsonp", produces = {"text/javascript", "application/javascript", "application/json"}, method = RequestMethod.GET)
@ResponseBody
public String handleActionJsonp(final HttpServletRequest request){
return "{test: 'blaat'}";
}
}
我尝试调用的网址:
http://host:8084/MyProject/server/api.jsonp?callback=test&_=1364980436087
调试输出:
11:13:57,776 DEBUG JsonpCallbackFilter:57 - test({test: 'blaat'});
11:13:57,776 DEBUG JsonpCallbackFilter:58 - Length: 22
结果:
test({test: 'bl
而不是预期的结果:
test({test: 'blaat'});