我正在尝试实施此Jsonp Filter
但是,每当我调用我的URL /server/api.jsonp?callback=something
时,它会切断响应的最后部分(ContentLength具有原始响应输出的长度。在这种情况下,因为{test: 'blaat'}
是我的原始响应输出,所以这将是15 - 见控制器。)至少这是我假设的,因为我得到的输出是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'});
答案 0 :(得分:1)
显然我必须首先设置内容长度然后写出输出。
右:
wrapper.setContentType("text/javascript;charset=UTF-8");
wrapper.setContentLength(jsonpResponse.length);
out.write(jsonpResponse);
错:
out.write(jsonpResponse);
wrapper.setContentType("text/javascript;charset=UTF-8");
wrapper.setContentLength(jsonpResponse.length);