如何在RESTEasy中启用JSONP?

标题说我的问题。 我需要将DTO包装到javascript方法回调中。 目前我按要求返回JSON。 但是在Ajax中使用它的问题是因为我将GET发送到其他域。 当然还有安全警察。

我有创意添加提供的想法。 你有任何例子,链接或建议如何做到这一点。

RESTEasy中没有对JSONP的明确支持,但是在应用程序中启用JSONP的一种简单方法是编写Servletfilter。

这里有一些链接可以帮助您编写filter:

  • jsonp-java:服务器端filter将任何响应包装到jsonp回调中

  • 从JAX-RS Web服务提供JSONP

  • 使用Spring的DelegatingFilterProxy为JSONP回调实现Servletfilter (如果您使用的是Spring)

当我有这个要求时,我最终写了自己的,因为我找到的所有例子似乎都没有说明。 以下是我编写自己的filter的建议:

  • 如果指定了回调参数,则仅包装响应(显然)

  • 如果响应内容类型是application/json则仅包装响应(或者如果您想支持更广泛的变体选择,只有在响应内容类型为application/jsonapplication/*+json时才进行换行)

  • 使用HttpServletResponseWrapper,以便您可以调用前向链( chain.doFilter )而无需将任何数据写入实际响应。 一旦前向链完成,您就可以检查内容类型,确保要将响应包装为JSONP,然后将捕获的数据与JSONP前缀和后缀一起写入实际响应。

  • 当您决定将响应包装为JSONP时,请确保将响应内容类型更改为text/javascript

如果您之前没有对Java EEfilter做过多少工作,您可能需要先阅读Java EE教程的相关部分: 过滤请求和响应 。

我为这个问题制定了草案解决方法。 试试吧。 此解决方案通过http get参数获取数据并转换为虚拟POST请求。

JQuery的:

 function call(){ var val = '{"routes":[{"arrivalAddress":{"fullAddress":"DME"},"destinationAddress":{"fullAddress":"SVO"}}],"carsCount":"1"}'; var jHandler = "doMap"; $.getJSON("http://xxx:yyy/app-0.0.0.1/rest/requestPrice?callback=" + jHandler + "&json=" + encodeURIComponent(val)+"&jsoncallback=?", null, null, "json"); } function doMap(obj){ alert(obj); } 

服务界面声明

 @POST @Path("requestPrice") @Produces("application/json") @Consumes("application/json") PriceResponse requestPrice(PriceRequest request) throws ServiceException; 

过滤类:

 import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import java.io.*; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class JSONPRequestFilter implements Filter { private String callbackParameter; public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (!(request instanceof HttpServletRequest)) { throw new ServletException("This filter can " + " only process HttpServletRequest requests"); } final HttpServletRequest httpRequest = (HttpServletRequest) request; final HttpServletResponse httpResponse = (HttpServletResponse) response; if (isJSONPRequest(httpRequest)) { RequestWrapper requestWrapper = new RequestWrapper(httpRequest); requestWrapper.setContentType("application/json; charset=UTF-8"); requestWrapper.setHeader("cache-control", "no-cache"); requestWrapper.setHeader("accept", "application/json"); requestWrapper.setCharacterEncoding("UTF-8"); requestWrapper.setBody(httpRequest.getParameter("json")); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(httpResponse) { @Override public ServletOutputStream getOutputStream() throws IOException { return new ServletOutputStream() { @Override public void write(int b) throws IOException { baos.write(b); } }; } @Override public PrintWriter getWriter() throws IOException { return new PrintWriter(baos); } public String getData() { return baos.toString(); } }; chain.doFilter(requestWrapper, responseWrapper); response.getOutputStream().write((getCallbackParameter(httpRequest) + "(").getBytes()); response.getOutputStream().write(baos.toByteArray()); response.getOutputStream().write(");".getBytes()); response.setContentType("text/javascript"); } else { chain.doFilter(request, response); } } private String getCallbackMethod(HttpServletRequest httpRequest) { return httpRequest.getParameter(callbackParameter); } private boolean isJSONPRequest(HttpServletRequest httpRequest) { String callbackMethod = getCallbackMethod(httpRequest); return (callbackMethod != null && callbackMethod.length() > 0); } private String getCallbackParameter(HttpServletRequest request) { return request.getParameter(callbackParameter); } public void init(FilterConfig filterConfig) throws ServletException { callbackParameter = filterConfig.getInitParameter("callbackParameter"); } public void destroy() { } void printRequest(HttpServletRequest request) throws IOException { { System.out.println("--------------Headers---------------"); Enumeration en = request.getHeaderNames(); while (en.hasMoreElements()) { String val = en.nextElement().toString(); System.out.println(val + " :"); Enumeration en1 = request.getHeaders(val); while (en1.hasMoreElements()) { System.out.println("\t" + en1.nextElement()); } } } { System.out.println("------------Parameters--------------"); Enumeration en = request.getParameterNames(); while (en.hasMoreElements()) { String val = en.nextElement().toString(); System.out.println(val + " :"); String[] en1 = request.getParameterValues(val); for (String val1 : en1) { System.out.println("\t" + val1); } } } System.out.println("---------------BODY--------------"); BufferedReader is = request.getReader(); String line; while ((line = is.readLine()) != null) { System.out.println(line); } System.out.println("---------------------------------"); System.out.println("ContentType: " + request.getContentType()); System.out.println("ContentLength: " + request.getContentLength()); System.out.println("characterEncodings: " + request.getCharacterEncoding()); System.out.println("AuthType: " + request.getAuthType()); System.out.println("ContextPath: " + request.getContextPath()); System.out.println("Method: " + request.getMethod()); } public static class RequestWrapper extends HttpServletRequestWrapper { Map headers = new HashMap(); int contentLength; BufferedReader reader; public RequestWrapper(HttpServletRequest request) { super(request); } public void setHeader(String key, String value) { headers.put(key, value); } ByteArrayInputStream bais; public void setBody(String body) { bais = new ByteArrayInputStream(body.getBytes()); contentLength = body.length(); headers.put("content-length", Integer.toString(contentLength)); } @Override public BufferedReader getReader() throws IOException { reader = new BufferedReader(new InputStreamReader(bais)); return reader; } @Override public ServletInputStream getInputStream() throws IOException { return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } }; } @Override public String getMethod() { return "POST"; } private String contentType; public void setContentType(String contentType) { this.contentType = contentType; headers.put("content-type", contentType); } @Override public String getContentType() { return contentType; } @Override public int getContentLength() { return contentLength; } @Override public String getHeader(String name) { String val = headers.get(name); if (val != null) { return val; } return super.getHeader(name); //To change body of overridden methods use File | Settings | File Templates. } @Override public Enumeration getHeaders(final String name) { return super.getHeaders(name); } @Override public Enumeration getHeaderNames() { final Enumeration en1 = super.getHeaderNames(); final Iterator it = headers.keySet().iterator(); return new Enumeration() { public boolean hasMoreElements() { return en1.hasMoreElements() || it.hasNext(); } public Object nextElement() { return en1.hasMoreElements() ? en1.nextElement() : (it.hasNext() ? it.next() : null); } }; } @Override public int getIntHeader(String name) { String val = headers.get(name); if (val == null) { return super.getIntHeader(name); } else { return Integer.parseInt(val); } } } } 

web.xml中

  JSONPRequestFilter xxxxx.JSONPRequestFilter  callbackParameter callback    JSONPRequestFilter /rest/*  

支持JSONP的增强function计划在RESTEasy 2.3.6 Final / 3.0-beta-4( https://issues.jboss.org/browse/RESTEASY-342 )中发布。 我能够通过简单地从GitHub复制代码来“反向”使用RESTEasy 2.3.5的项目。

RESTEasy会根据注释自动选择新的提供程序。 一旦在url中看到名为“callback”的查询参数,它就会自动将结果包装在js回调中。 这与JQuery向服务器发送的JSONP请求兼容。

接下来来自@talawahdotnet,我正在使用RestEasy 3.0.9.Final,并且支持JSONP,一旦启用,任何带有“回调”查询参数的请求都将被包装为JSONP。 我正在使用JBoss,所以完整的文档在这里用于其他容器。 这是我必须要做的步骤:

  1. 在你的web.xml中添加:

      resteasy.providers org.jboss.resteasy.plugins.providers.jackson.JacksonJsonpInterceptor  
  2. 确保您有一个WEB-INF / jboss-deployment-structure.xml:

            
  3. 确保你的pom.xml中有一个resteasy-jackson-provider依赖项,例如:

      org.jboss.resteasy resteasy-jackson-provider provided  

Resteasy 声称在3.x版本中支持JSONP开箱即用:

如果您正在使用Jackson,Resteasy可以通过添加提供程序org.jboss.resteasy.plugins.providers.jackson.JacksonJsonpInterceptor(Jackson2JsonpInterceptor,如果您使用Jackson2提供程序)来启用JSONP,以进行部署。 如果响应的媒体类型是json并且给出了回调查询参数,则响应将是一个javascript片段,其中包含由callback参数定义的方法的方法调用。 例如:

GET / resources / stuff?callback = processStuffResponse会产生这样的响应:

processStuffResponse()这支持jQuery的默认行为。

您可以通过设置callbackQueryParameter属性来更改回调参数的名称。

但是,由于RESTEASY-1168 ,它似乎被打破了:Jackson2JsonpInterceptor没有渲染结束括号

所以foo({"foo":"bar"}被渲染而不是foo({"foo":"bar"})

这会导致“Uncaught SyntaxError:Unexpected Identifier”错误

我已经提交了一个带有修复的pull-request ,希望它应该进入下一个版本3.0.12

我知道这个问题很老了,但是当你搜索重新出现的jsonp问题时,它会显示在Google的第一页上,所以我决定更新它