Я пытаюсь реализовать это Jsonp Filter.
Однако, когда я вызываю свой url /server/api.jsonp?callback=something
, он вырезает последнюю часть ответа (ContentLength имеет длину исходного отклика. В этом случае это будет 15, так как {test: 'blaat'}
- это мой исходный ответ - см. Контроллер).
atleast это то, что я предполагаю, так как выход я получаю test({test: 'bl
. Кто-нибудь знает, как заставить фильтр работать и отправить правильный ответ? (я даже пытаюсь заставить Content-Length - см JsonpCallbackFilter)Неверный ответ фильтра Spring MVC Jsonp. (Сокращение длины ответа от ответа)
Фильтр:
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() {
}
}
Generic Response Wrapper:
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);
}
}
Пользовательский фильтр OutputStream:
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 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'}";
}
}
Url Пытаюсь позвонить: выход
http://host:8084/MyProject/server/api.jsonp?callback=test&_=1364980436087
Debug:
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'});