1

我正在尝试实现这个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'});
4

1 回答 1

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);
于 2013-04-03T09:41:29.297 回答