Как включить JSONP в RESTEasy?

Название говорит о моей проблеме. Мне нужно обернуть DTO в обратный вызов метода javascript. В настоящее время я возвращаюсь по запросу JSON. Но проблема с использованием этого в Ajax, потому что я отправляю GET в другой домен. и, конечно же, полиции безопасности.

У меня есть идея создать дополнение. У вас есть пример, ссылки или предложения, как это можно сделать.

Ответ 1

В RESTEasy нет явной поддержки JSONP, однако один простой способ включить JSONP в вашем приложении - это написать сервлет-фильтр.

Вот несколько ссылок, которые могут помочь вам написать фильтр:

Когда у меня было это требование, я закончил писать свои собственные, так как ни один из примеров, которые я нашел, как бы не прибил его. Вот мой совет для написания собственного фильтра:

  • только завершает ответ, если задан параметр обратного вызова (очевидно)

  • завершает только ответ, если тип содержимого ответа application/json (или если вы хотите поддерживать более широкий выбор вариантов, только оберните, если тип содержимого ответа application/json или application/*+json)

  • используйте HttpServletResponseWrapper, чтобы вы могли ссылаться на прямую цепочку (chain.doFilter) без записи каких-либо данных в реальный ответ. Как только цепочка будет завершена, вы можете проверить тип содержимого, убедитесь, что хотите отложить ответ как JSONP, а затем записать полученные данные в ответ реальный, а также префикс JSONP и суффикс.

  • когда вы решите обернуть ответ как JSONP, убедитесь, что вы изменили тип содержимого ответа на text/javascript

Если вы еще ничего не делали с Java EE Filters, вы можете сначала прочитать соответствующий раздел учебника Java EE: Запросы фильтрации и Ответы.

Ответ 2

Я делаю проект обходного пути для этой проблемы. Попробуй. Это решение принимает данные через http get parameters и переводит на виртуальный запрос 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<String, String> headers = new HashMap<String, String>();

        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

<filter>
    <filter-name>JSONPRequestFilter</filter-name>
    <filter-class>xxxxx.JSONPRequestFilter</filter-class>
    <init-param>
        <param-name>callbackParameter</param-name>
        <param-value>callback</param-value>
    </init-param>
</filter>

<filter-mapping>
  <filter-name>JSONPRequestFilter</filter-name>
  <url-pattern>/rest/*</url-pattern>
</filter-mapping>

Ответ 3

Расширение поддержки JSONP планируется выпустить в RESTEasy 2.3.6 Final/3.0-beta-4 (https://issues.jboss.org/browse/RESTEASY-342). Я смог "поддержать" мой проект, который использует RESTEasy 2.3.5, просто скопировав их код из GitHub.

RESTEasy автоматически выбирает нового провайдера на основе аннотации. Он автоматически работает, завершая ваши результаты в обратном вызове js, как только он видит параметр запроса с именем "обратный вызов" в URL-адресе. Это совместимо с тем, что JQuery отправляет на сервер для запросов JSONP.

Ответ 4

Чтобы перейти от @talawahdotnet, я использую RestEasy 3.0.9.Final, и есть поддержка JSONP, после включения любой запрос с параметром запроса "обратный вызов" будет завернут как JSONP. Я использую JBoss, поэтому полные документы здесь для других контейнеров. Вот шаги, которые я должен был сделать:

  • В вашем web.xml добавьте:

    <context-param>
        <param-name>resteasy.providers</param-name>
        <param-value>org.jboss.resteasy.plugins.providers.jackson.JacksonJsonpInterceptor</param-value>
    </context-param>
    
  • Убедитесь, что у вас есть WEB-INF/jboss-deployment-structure.xml с:

    <jboss-deployment-structure>
        <deployment>
            <dependencies>
                <module name="org.jboss.resteasy.resteasy-jackson-provider" services="import" annotations="true"/>
            </dependencies>
        </deployment>
    </jboss-deployment-structure>
    
  • Убедитесь, что у вас есть зависимость rest -asy-jackson-provider в вашем pom.xml, что-то вроде:

    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jackson-provider</artifactId>
        <scope>provided</scope>
    </dependency>
    

Ответ 5

Restaasy утверждает, что поддерживает JSONP из версии 3.x:

Если вы используете Джексона, у Resteasy есть JSONP, который вы можете включить добавление провайдера org.jboss.resteasy.plugins.providers.jackson.JacksonJsonpInterceptor(Jackson2JsonpInterceptor, если вы используете поставщика Jackson2), чтобы ваши развертывания. Если тип ответа на носитель - json и параметр запроса обратного вызова, ответ будет javascript фрагмент с вызовом метода метода, определяемого обратным вызовом параметр. Например:

GET/resources/stuff? callback = processStuffResponse будет производить это Ответ:

processStuffResponse() Это поддерживает значение по умолчанию поведение jQuery.

Вы можете изменить имя параметра обратного вызова, установив свойство callbackQueryParameter.

Однако, кажется, что он сломан из-за RESTEASY-1168: Jackson2JsonpInterceptor не отображает закрывающий скобок

Итак, foo({"foo":"bar"} отображается вместо foo({"foo":"bar"})

И это приводит к ошибке "Неактивировать SyntaxError: Неожиданный идентификатор"

Я отправил pull-request с исправлением и, надеюсь, он должен попасть в следующую версию 3.0.12

Я знаю, что этот вопрос довольно старый, но он отображается на первой странице Google, когда вы ищете проблемы с resteasy jsonp, поэтому я решил обновить его