2013-04-03 2 views
1

Я пытаюсь реализовать это 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'}); 

ответ

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); 
Смежные вопросы