1

この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'}";
    }
}

呼び出したい URL:

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