Как включить 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, поэтому я решил обновить его