Title say about my issue. I need wrap DTO in to a javascript method callback. Currently I return on request JSON. But problem with using this in Ajax because I send GET to other domain. and of course security police.
I have idea to create addition provide. Have you any example, links or suggestion how can do this.
There's no explicit support for JSONP in RESTEasy, however one easy way to enable JSONP in your application is to write a Servlet Filter.
Here's a few links that can help you write a filter:
jsonp-java: server side filter wraps any response into a jsonp callback
Serving up JSONP from your JAX-RS Web Services
Implementing a Servlet Filter for JSONP callback with Spring’s DelegatingFilterProxy (if you're using Spring)
When I had this requirement I ended up writing my own since none of the examples I found seemed to quite nail it. Here's my advice for writing your own filter:
only wrap the response if a callback parameter is specified (obviously)
only wrap the response if the response content type is application/json (or if you want to support a wider selection of variants, only wrap if the response content type is application/json or application/*+json)
use an HttpServletResponseWrapper so that you can invoke the forward chain (chain.doFilter) without writing any data to the real response. Once the forward chain is complete you can then check the content type, make sure you want to wrap the response as JSONP, then write the captured data into the real response, along with the JSONP prefix and suffix.
when you do decide to wrap the response as JSONP, make sure you change the response content type to text/javascript
If you haven't done much with Java EE Filters before, you may want to read the relevant section of the Java EE tutorial first: Filtering Requests and Responses.
I make draft workaround for this problem. Try it. This solution takes data via http get parameters and translate to virtual POST request.
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);
}
Declaration in Service interface
#POST
#Path("requestPrice")
#Produces("application/json")
#Consumes("application/json")
PriceResponse requestPrice(PriceRequest request) throws ServiceException;
Filter class:
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>
An enhancement to support JSONP is scheduled to be released in RESTEasy 2.3.6 Final/3.0-beta-4 (https://issues.jboss.org/browse/RESTEASY-342). I was able to "backport" it my project which uses RESTEasy 2.3.5 by simply copying their code from GitHub.
RESTEasy automatically picks up the new provider based on the annotation. It works automatically by wrapping your results in a js callback once it sees a query parameter named "callback" in the url. This is compatible with what JQuery sends to the server for JSONP requests.
To follow on from #talawahdotnet, I'm using RestEasy 3.0.9.Final and there is support for JSONP, once enabled, any request with a "callback" query parameter will be wrapped as JSONP. I'm using JBoss so the full docs are here for other containers. Here's the steps I had to do:
In your web.xml add:
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>org.jboss.resteasy.plugins.providers.jackson.JacksonJsonpInterceptor</param-value>
</context-param>
Make sure you have a WEB-INF/jboss-deployment-structure.xml with:
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.jboss.resteasy.resteasy-jackson-provider" services="import" annotations="true"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
Make sure you have a resteasy-jackson-provider dependency in your pom.xml, something like:
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<scope>provided</scope>
</dependency>
Resteasy claims to support JSONP out of the box in 3.x version:
If you're using Jackson, Resteasy has JSONP that you can turn on by
adding the provider
org.jboss.resteasy.plugins.providers.jackson.JacksonJsonpInterceptor
(Jackson2JsonpInterceptor if you're using the Jackson2 provider) to
your deployments. If the media type of the response is json and a
callback query parameter is given, the response will be a javascript
snippet with a method call of the method defined by the callback
parameter. For example:
GET /resources/stuff?callback=processStuffResponse will produce this
response:
processStuffResponse() This supports the default
behavior of jQuery.
You can change the name of the callback parameter by setting the
callbackQueryParameter property.
However, it seems that it is broken due to RESTEASY-1168: Jackson2JsonpInterceptor does not render closing bracket
So
foo({"foo":"bar"}
is rendered instead of
foo({"foo":"bar"})
And that causes "Uncaught SyntaxError: Unexpected Identifier" error
I have submitted a pull-request with a fix and hopefully it should get into next release 3.0.12
I know that this question is pretty old, but it is shown on the first page of Google when you search for resteasy jsonp problems, so I decided to update it
Related
I have implemented filter and I have called getEntityStream of ContainerRequestContext and set the exact value back by using setEntitystream. If i use this filter then #FormParameter data becomes null and if i don't use filter then everything will be fine (as I am not calling getEntityStream) and i have to use filter to capture request data.
Note: I am getting form params from MultivaluedMap formParams but not from #FormParameter.
Environment :- Rest Easy API with Jboss Wildfly 8 server.
#Provider
#Priority(Priorities.LOGGING)
public class CustomLoggingFilter implements ContainerRequestFilter, ContainerResponseFilter{
final static Logger log = Logger.getLogger(CustomLoggingFilter.class);
#Context
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext requestContext)
throws IOException {
MDC.put("start-time", String.valueOf(System.currentTimeMillis()));
String entityParameter = readEntityStream(requestContext);
log.info("Entity Parameter :"+entityParameter);
}
private String readEntityStream(ContainerRequestContext requestContext){
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
final InputStream inputStream = requestContext.getEntityStream();
final StringBuilder builder = new StringBuilder();
int read=0;
final byte[] data = new byte[4096];
try {
while ((read = inputStream.read(data)) != -1) {
outStream.write(data, 0, read);
}
} catch (IOException e) {
e.printStackTrace();
}
byte[] requestEntity = outStream.toByteArray();
if (requestEntity.length == 0) {
builder.append("");
} else {
builder.append(new String(requestEntity));
}
requestContext.setEntityStream(new ByteArrayInputStream(requestEntity) );
return builder.toString();
}
return null;
}
}
class customResource
{
//// This code is not working
#POST
#Path("voiceCallBack")
#ApiOperation(value = "Voice call back from Twilio")
public void voiceCallback(#FormParam("param") String param)
{
log.info("param:" + param);
}
// This code is working
#POST
#Path("voiceCallBackMap")
#ApiOperation(value = "Voice call back from Twilio")
public void voiceCallbackMap(final MultivaluedMap<String, String> formParams)
{
String param = formParams.getFirst("param");
}
}
please suggest me solution & Thanks in Advance.
I found during run time that instance of the entity stream (from http request) is of type org.apache.catalina.connector.CoyoteInputStream (I am using jboss-as-7.1.1.Final). But we are setting entity stream with the instance of java.io.ByteArrayInputStream. So Resteasy is unable to bind individual formparmeters.
There are two solutions for this you can use any one of them :
Use this approach How to read JBoss Resteasy's servlet request twice while maintaing #FormParam binding?
Get form parameters like this:
#POST
#Path("voiceCallBackMap")
#ApiOperation(value = "Voice call back from Twilio")
public void voiceCallbackMap(final MultivaluedMap<String, String> formParams)
{
String param = formParams.getFirst("param");
}
In my app I am using netflix zuul to route a request from a microservice (gateway) to another. The requests are being routed fine but I also want to introduce some parameters in the request body before it is routed to the appropriate microservice. For this I am using Zuul pre filter like this.
public class SimpleFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(SimpleFilter.class);
#Override
public String filterType() {
return "pre";
}
#Override
public int filterOrder() {
return 1;
}
#Override
public boolean shouldFilter() {
return true;
}
#Override
public Object run() {
try {
RequestContext context = RequestContext.getCurrentContext();
InputStream in = (InputStream) context.get("requestEntity");
if (in == null) {
in = context.getRequest().getInputStream();
}
String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
// body = "request body modified via set('requestEntity'): "+ body;
body = body.toUpperCase();
context.set("requestEntity", new ByteArrayInputStream(body.getBytes("UTF-8")));
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return null;
}
}
For now I am just trying to change the body to upper case but the microservice to which this request is routed doesn't receive the modified body (upper case). Instead it receives the original one. Am I doing something wrong. Any help would be appreciated. Thanks !!
Was able to do the following - transform a GET request to a POST request, and add body content to the (proxied) POST request.
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
context.addZuulRequestHeader("Content-Type", "application/x-www-form-urlencoded");
String body = String.format("a=%s&b=%s", a, b);
final byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
context.setRequest(new HttpServletRequestWrapper(context.getRequest()) {
#Override
public ServletInputStream getInputStream() {
return new ServletInputStreamWrapper(bytes);
}
#Override
public int getContentLength() {
return bytes.length;
}
#Override
public long getContentLengthLong() {
return bytes.length;
}
#Override
public String getMethod() {
return "POST";
}
});
return null;
}
try this one It's may be work in your case .
requestContext.getCurrentContext().put("requestEntity", new ByteArrayInputStream(body.getBytes("UTF-8")));
Turned out this method cannot change the request body within the requestContext. Truly in the requestContext, a new field "requestEntity" is added, however, the request body from context.getRequest().getInputStream() remains the same after this operation.
You can modify the request body, see this answer for an example. You just need to wrap the new request data and make sure you correctly report it's new content length.
I have a REST endpoint #POST where the form params are null when the Content-Type is application/x-www-form-urlencoded. There is a ContainerRequestFilter earlier in the chain (code at the bottom) that takes the request, changes the stream to a BufferedInputStream, and then logs the request. If I remove this logging code, the endpoint has the correct form params. Otherwise, they're null and I can't figure out why.
Now if I use application/json, my endpoint has the correct params regardless if the logger is enabled or disabled.
I need application/x-www-form-urlencoded because the REST endpoint needs to redirect and browsers prevent redirection if the request isn't standard (preflight)
REST Endpoint that isn't working (OAuthRequest has null members)
#Stateless
#Path("v1/oauth2")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces(MediaType.APPLICATION_JSON)
public class OAuthTokenResource {
#POST
public Response getToken(#Form OAuthRequest oauthRequest) {
...
}
OAuthRequest
public class OAuthRequest {
#FormParam(OAuthParam.CLIENT_ID)
#JsonProperty(OAuthParam.CLIENT_ID)
private String clientId;
#URL
#FormParam(OAuthParam.REDIRECT_URI)
#JsonProperty(OAuthParam.REDIRECT_URI)
private String redirectUri;
#FormParam(OAuthParam.USERNAME)
private String username;
#FormParam(OAuthParam.PASSWORD)
private String password;
...
}
Logging Filter
#Override
public void filter(final ContainerRequestContext context) throws IOException {
...
if (logEntity && context.hasEntity()) {
context.setEntityStream(logInboundEntity(builder, context.getEntityStream(), context.getMediaType()));
}
logger.debug(builder.toString());
}
private InputStream logInboundEntity(final StringBuilder builder, InputStream stream, MediaType mediaType) throws IOException {
if (!stream.markSupported()) {
stream = new BufferedInputStream(stream);
}
stream.mark(maxEntitySize + 1);
final byte[] entity = new byte[maxEntitySize + 1];
final int entitySize = stream.read(entity);
if ( entitySize > 0 ) {
String body = new String(entity, 0, Math.min(entitySize, maxEntitySize), StandardCharsets.UTF_8);
builder.append("\nBody: ");
builder.append(body);
}
if (entitySize > maxEntitySize) {
builder.append(MORE_INDICATOR);
}
stream.reset();
return stream;
}
Okay I am still not sure why #Form and #FormParam does not work if the InputStream is read during the filter chain.
But, I discovered a workaround as follows.
#POST
public Response getToken(MultivaluedMap<String, String> formParams) {
...
}
This provides the same behavior as during application/json as the params are already set even if the InputStream has been consumed.
However ultimately we went with disabling logging of the request body in our filter for security reasons.
I got a HttpServletRequest request in my Spring Servlet which I would like to forward AS-IS (i.e. GET or POST content) to a different server.
What would be the best way to do it using Spring Framework?
Do I need to grab all the information and build a new HTTPUrlConnection? Or there is an easier way?
Discussions of whether you should do forwarding this way aside, here's how I did it:
package com.example.servlets;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Enumeration;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.example.servlets.GlobalConstants;
#SuppressWarnings("serial")
public class ForwardServlet extends HttpServlet {
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
forwardRequest("GET", req, resp);
}
#Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) {
forwardRequest("POST", req, resp);
}
private void forwardRequest(String method, HttpServletRequest req, HttpServletResponse resp) {
final boolean hasoutbody = (method.equals("POST"));
try {
final URL url = new URL(GlobalConstants.CLIENT_BACKEND_HTTPS // no trailing slash
+ req.getRequestURI()
+ (req.getQueryString() != null ? "?" + req.getQueryString() : ""));
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(method);
final Enumeration<String> headers = req.getHeaderNames();
while (headers.hasMoreElements()) {
final String header = headers.nextElement();
final Enumeration<String> values = req.getHeaders(header);
while (values.hasMoreElements()) {
final String value = values.nextElement();
conn.addRequestProperty(header, value);
}
}
//conn.setFollowRedirects(false); // throws AccessDenied exception
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(hasoutbody);
conn.connect();
final byte[] buffer = new byte[16384];
while (hasoutbody) {
final int read = req.getInputStream().read(buffer);
if (read <= 0) break;
conn.getOutputStream().write(buffer, 0, read);
}
resp.setStatus(conn.getResponseCode());
for (int i = 0; ; ++i) {
final String header = conn.getHeaderFieldKey(i);
if (header == null) break;
final String value = conn.getHeaderField(i);
resp.setHeader(header, value);
}
while (true) {
final int read = conn.getInputStream().read(buffer);
if (read <= 0) break;
resp.getOutputStream().write(buffer, 0, read);
}
} catch (Exception e) {
e.printStackTrace();
// pass
}
}
}
Obviously this could use a bit of work with regard to error handling and the like but it was functional. I stopped using it, however, because it was easier in my case to make calls directly to the CLIENT_BACKEND than to deal with cookies, auth, etc. across two distinct domains.
I also needed to do the same, and after some non optimal with Spring controllers and RestTemplate, I found a better solution: Smiley's HTTP Proxy Servlet. The benefit is, it really does AS-IS proxying, just like Apache's mod_proxy, and it does it in a streaming way, without caching the full request/response in the memory.
Simply, you register a new servlet to the path you want to proxy to another server, and give this servlet the target host as an init parameter. If you are using a traditional web application with a web.xml, you can configure it like following:
<servlet>
<servlet-name>proxy</servlet-name>
<servlet-class>org.mitre.dsmiley.httpproxy.ProxyServlet</servlet-class>
<init-param>
<param-name>targetUri</param-name>
<param-value>http://target.uri/target.path</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>proxy</servlet-name>
<url-pattern>/mapping-path/*</url-pattern>
</servlet-mapping>
or, of course, you can go with the annotation config.
If you are using Spring Boot, it is even easier: You only need to create a bean of type ServletRegistrationBean, with the required configuration:
#Bean
public ServletRegistrationBean proxyServletRegistrationBean() {
ServletRegistrationBean bean = new ServletRegistrationBean(
new ProxyServlet(), "/mapping-path/*");
bean.addInitParameter("targetUri", "http://target.uri/target.path");
return bean;
}
This way, you can also use the Spring properties that are available in the environment.
You can even extend the class ProxyServlet and override its methods to customize request/response headers etc, in case you need.
Update: After using Smiley's proxy servlet for some time, we had some timeout issues, it was not working reliably. Switched to Zuul from Netflix, didn't have any problems after that. A tutorial on configuring it with Spring Boot can be found on this link.
Unfortunately there is no easy way to do this. Basically you'll have to reconstruct the request, including:
correct HTTP method
request parameters
requests headers (HTTPUrlConnection doesn't allow to set arbitrary user agent, "Java/1.*" is always appended, you'll need HttpClient)
body
That's a lot of work, not to mention it won't scale since each such proxy call will occupy one thread on your machine.
My advice: use raw sockets or netty and intercept HTTP protocol on the lowest level, just replacing some values (like Host header) on the fly. Can you provide more context, why so you need this?
#RequestMapping(value = "/**")
public ResponseEntity route(HttpServletRequest request) throws IOException {
String body = IOUtils.toString(request.getInputStream(), Charset.forName(request.getCharacterEncoding()));
try {
ResponseEntity<Object> exchange = restTemplate.exchange(firstUrl + request.getRequestURI(),
HttpMethod.valueOf(request.getMethod()),
new HttpEntity<>(body),
Object.class,
request.getParameterMap());
return exchange;
} catch (final HttpClientErrorException e) {
return new ResponseEntity<>(e.getResponseBodyAsByteArray(), e.getResponseHeaders(), e.getStatusCode());
}
}
If you are forced to use spring, please check the rest template method exchange to proxy requests to a third party service.
Here you can find a working example.
Use Spring Cloud Gateway
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway-mvc</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2020.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Controller
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.mvc.ProxyExchange;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
#RestController
public class Proxy extends BaseController {
private String prefix="/proxy";
private String Base="localhost:8080/proxy"; //destination
void setHeaders(ProxyExchange<?> proxy){
proxy.header("header1", "val1"); //add additional headers
}
#GetMapping("/proxy/**")
public ResponseEntity<?> proxyPath(#RequestParam MultiValueMap<String,String> allParams, ProxyExchange<?> proxy) throws Exception {
String path = proxy.path(prefix); //extract sub path
proxy.header("Cache-Control", "no-cache");
setHeaders(proxy);
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(Base + path).queryParams(allParams).build();
return proxy.uri(uriComponents.toUri().toString()).get();
}
#PutMapping("/proxy/**")
public ResponseEntity<?> proxyPathPut(ProxyExchange<?> proxy) throws Exception {
String path = proxy.path(prefix);
setHeaders(proxy);
return proxy.uri(Base + path).put();
}
I'm trying to make Cross Site Request using GWT Request builder, which i couldn't get it to work yet. As you can see, this is much of a Sample GWT Project and i have gone through https://developers.google.com/web-toolkit/doc/latest/tutorial/Xsite . But still i'm missing something.
I'm Posting the code here. What am i missing ..?
package com.gwt.reqbuilder.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Window;
public class GWTRequestBuilder implements EntryPoint
{
private static final String JSON_URL = "http://localhost:8000/?q=ABC&callback=callback125";
public void onModuleLoad()
{
GWTPOSTHTTP();
}
public void GWTPOSTHTTP()
{
String postUrl="http://localhost:8000";
String requestData="q=ABC&callback=callback125";
RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, postUrl);
try {
builder.sendRequest(requestData.toString(), new RequestCallback()
{
public void onError(Request request, Throwable e)
{
Window.alert(e.getMessage());
}
public void onResponseReceived(Request request, Response response)
{
if (200 == response.getStatusCode())
{
Window.alert(response.getText());
} else {
Window.alert("Received HTTP status code other than 200 : "+ response.getStatusText());
}
}
});
} catch (RequestException e) {
// Couldn't connect to server
Window.alert(e.getMessage());
}
}
}
Actually we can make Cross Site Requests from GWT RequestBuilder if we can set in Servlet Response Header
Response.setHeader("Access-Control-Allow-Origin","http://myhttpserver");
It's working Cool , if anyone need the GWT Project and Python Servlet, please do let me know, i can upload the files.
GWT Client Code : https://github.com/manikandaraj/MLabs/tree/master/GWT/GWTClient
You've missed to finish reading the tutorial.
Direct quote from the tutorial :
The RequestBuilder code is replaced by a call to the getJson method. So you no longer need the following code in the refreshWatchList method:
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
displayError("Couldn't retrieve JSON");
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
updateTable(asArrayOfStockData(response.getText()));
} else {
displayError("Couldn't retrieve JSON (" + response.getStatusText()
+ ")");
}
}
});
} catch (RequestException e) {
displayError("Couldn't retrieve JSON");
}
Which is broadly what you've got, and should be replaced by a JSNI function given in the tutorial a few lines below :
/**
* Make call to remote server.
*/
public native static void getJson(int requestId, String url,
StockWatcher handler) /*-{
var callback = "callback" + requestId;
// [1] Create a script element.
var script = document.createElement("script");
script.setAttribute("src", url+callback);
script.setAttribute("type", "text/javascript");
// [2] Define the callback function on the window object.
window[callback] = function(jsonObj) {
// [3]
handler.#com.google.gwt.sample.stockwatcher.client.StockWatcher::handleJsonResponse(Lcom/google/gwt/core/client/JavaScriptObject;)(jsonObj);
window[callback + "done"] = true;
}
...