Assume that I have a website whose static assets are hosted in CDN (say, AWS CloudFront), however, all the GWT-RPC calls will be handled in the domain hosts. How can I achieve this in GWT?
As #robert mentioned, CORS is another option, but it doesn't require any changes in your client-side code - if the browser is new enough to support CORS at all, then all you do is make the call to the remote server, and make sure that the remote server supports it.
Depending on which server you are using, the support will be slightly different. https://www.w3.org/wiki/CORS_Enabled has a list of different servers and how you might enable CORS, depending on what you are using, and whether you enable it across your entire server, or just in a single part of the application.
For example, in Jetty:
<filter>
<filter-name>cross-origin</filter-name>
<filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cross-origin</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
While in Tomcat:
CorsFilter
org.apache.catalina.filters.CorsFilter
CorsFilter
/*
It is also possible to modify your RemoteServiceServlet class to handle this, but it comes with the disadvantage of needing to more fully understand the spec and make sure you handle it all correctly.
As with JSONP, there are important security implications of allowing cross-domain requests. Unlike JSONP, the CORS spec includes features to mitigate this, and ensure that the browser doesn't attempt to make calls to your remote server from the wrong host page - you can restrict calls so that they only come from specific domains. The specific header is Access-Control-Allow-Origin, and while it can be assigned to *, meaning "all servers", you likely want to restrict it to avoid potential XSRF attacks against your application - for the above examples this is managed via init-parameters, check your container's documentation for specific details. Additionally, changing the url-pattern can restrict the urls that these filters apply to can limit what can be requested remotely.
You could try to use CORS (https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS)
Something like this:
public class CrossSiteRpcRequestBuilder extends RpcRequestBuilder {
#Override
protected RequestBuilder doCreate(String serviceEntryPoint) {
RequestBuilder requestBuilder=super.doCreate(serviceEntryPoint);
requestBuilder.setIncludeCredentials(true);
return requestBuilder;
}
}
public class CrossSiteRpcRequestBuilderFactory {
public RpcRequestBuilder get() {
return new CrossSiteRpcRequestBuilder();
}
}
RpcRequestBuilder rpcRequestBuilder=((CrossSiteRpcRequestBuilderFactory) GWT.create(CrossSiteRpcRequestBuilderFactory.class)).get();
rpcRequestBuilder.create("{YOUR_HOST}/cors_handshake");
rpcRequestBuilder.setContentType("text/x-gwt-rpc; charset=utf-8");
rpcRequestBuilder.setRequestData("cors handshake");
rpcRequestBuilder.setCallback(new RequestCallback() {
...
});
RequestBuilder r=rpcRequestBuilder.finish();
r.send();
An alternative would be to use your server as a proxy to the remote server (bandwidth).
In conclusion:
I would use JsonpRequestBuilder instead of RPC, its less convenient, but guaranteed to work (unlike CORS).
See http://www.gwtproject.org/doc/latest/tutorial/Xsite.html for details.
Related
I separated GWT - static code is on CDN and dynamic is on a different server.
I configured this CORS filter on Tomcat7 and it works fine:
http://software.dzhuvinov.com/cors-filter-installation.html
However I'm still struggling with getting Cookies to work with GWT and CORS.
I mainly need it for XSRF protection (and few other things):
https://developers.google.com/web-toolkit/doc/latest/DevGuideSecurityRpcXsrf
It looks like I have to set withcredentials=true in XMLHttpRequest.
Does anyone know how to do it in GWT?
By default Cookies are not sent with CORS. If you want them, you have to set the withCredentials attribute to the low-level XMLHttpRequest used by GWT. Unfortunately there is no way to set it from your java code.
A simple hack is that you maintain your own version of XMLHttpRequest.java in your source tree (use the same namespace), and modify the create() method in this way:
private static native XMLHttpRequest create(String responseType) /*-{
[...]
xhr.withCredentials = true;
return xhr;
}-*/;
Note: from server side you have to sent this header as well:
Access-Control-Allow-Credentials: true
Otherwise, the normal way to deal with authentication in GWT is that you use special headers with the auth info and read it in the server side.
builder.setHeader("X-My-Authenticated-Header", "whatever");
EDIT: as t.broyer points in his comment below, a RequestBuilder.setIncludeCredentials method is in 2.5.1-rc1. So if you are using this release, call this method in when creating your builder.
I am trying to implement the work around suggested on this link
http://raibledesigns.com/rd/entry/how_to_do_cross_domain
My existing Servlet on my server looks like
#SuppressWarnings("serial")
public class ContactsServiceImpl extends RemoteServiceServlet implements ContactsService
{
...
How do I modify this to get the cross domain to work. Do I need to make any changes on the client side?
It isn't the GWT Same Origin Policy - it is the browser itself! The browser won't normally allow any XHR call to go out to a server that isn't the same server the page was loaded from.
The link you mentioned lets your server act as a proxy - thats one way to let the client talk to another server. The steps they take (create a servlet that forwards requests, configure it to point at the other server you want to use) do not require changes to the client.
Another option is to use the Cross Origin Resource Sharing - a way for the server to specify that the browser is allowed to contact it, even across domains. The catch: not all browsers support it.
I am trying to consume a restful Web service using camel.
For that I am configuring dynamic endpoint url as the RESTful url is created at the runtime. Everytime I am checking if the particular endpoint url is registered as a route in my camel context using following method of CamelContext class.
Endpoint hasEndpoint(String uri);
In this case, if the endpoint is not registered then I add a route to my camel context using a custom Route Builder.
I am using camel HTTP component for this. This is working fine for me as of now.
However, I believe performance wise this is not good as everytime I have to check if a route is registered with the camel context and if not then register the same before making the webservice call.
Can some body please tell me if there is a better way to consume RESTful Web services in camel?
I also want to know if the RESTful webservice I am consuming uses OAuth 2.0 protocol, do I need to change anything in my code as I am just consuming it?
Regards, Nilotpal
Thanks for your reply.
I am checking if the route is already exists to make sure I don't end up adding duplicate route(s) to the camel context.
Regarding long lived routes and route dynamics, can u please explain a bit regarding this? How do I implement route dynamics?
It would also be helpful if you could point me to some CXF-RS producer example.. I read the documentation of CXFRS but could not understand it clearly.
Thanks
Nilotpal
Exactly why do you need to check if the route is registred or not before making the call? You should perhaps setup a more long lived route and route dynamic towards resfull resources.
As for Rest with camel, I think the HTTP component does a great job, but there are higher level components to use as well, more designed for REST.
CXFRS and Restlet, producer examples for restlet can be found in the Apache Camel source unit tests, such as this RestletProducerGetTest.java.
As for oAuth 2.0, Camel has some oAuth support built-in, especially for google. Look for the gauth component. There is even a tutorial, however it might not be aligned with your case, it still might give some background so you could solve your issues: http://camel.apache.org/tutorial-oauth.html
CamelContext context = new DefaultCamelContext();
My Aim
I am trying to intercept the incoming request and based on the ip of the incoming request i want to invoke dynamic endpoint of get offers
context.addRoutes(new RouteBuilder(){
public void configure(){
from("jetty:localhost:9000/offers")
.process(new Processor(){
public void process(Exchange exchange) throws Exception {
//getting the request object
HttpServletRequest req = exchange.getIn().getBody(HttpServletRequest.class);
//Extracting information from the request
String requestIP=req.getRemoteAddr();
/**
* After getting the ip address i do necessay processing
* and then add a property to exchange object.
* Destination ip address is the address to which i want to
* send my request
*/
exchange.setProperty("operatorAddress",destinationIpAddress);
}
})
.to("direct:getOffers")
.end();
}
});
Now i will invoke the getOffers endpoint
so first i will register it
context.addRoutes(new RouteBuilder(){
public void configure(){
from("direct:getOffers")
.toD("jetty:${property.operatorAddress}/api/v2.0/offers?
bridgeEndpoint=true")
.end();
}
});
so we can access the operatorAddress property of exchange object as
${property.operatorAddress}
also when we have dynamic routes then we need to call
.toD() and not .to()
I'm making a ajax request with type:'DELETE' but somehow the request is not going inside the ServeResources(request,response) method (overridden from GenericPortlet class).
does anyone has an idea that why "Delete" and "Put" are not working with portal application(JSR 286) and How to get rid of that?
Thanks,
HTTP PUT/DELETE are some what protected methods, most of the web/application servers disable these methods by default, that could be the reason why you are not seeing your requests on server side. AFAIK it is independent of portal environment and handled by web/application server. You need to do some configuration changes on your server.
I have a web service in the form `http://....../methodName
It returns a jsonp result such as:
methodName(["a":"a", "b":"b"])
GWT provides JsonpRequestBuilder class to parse jsonp.
JsonpRequestBuilder rb = new JsonpRequestBuilder();
rb.setCallbackParam("callback");
rb.requestObject("http://...../methodName", new AsyncCallback<TestJS>(){
...
});
This structure makes a request to url :
"http://...../methodName/?callback=__gwt_jsonp_P0.onSuccess".
My web service returns a callback with methodName not with __gwt_json.....
So gwt could not create a JavaScriptObject from that response.
Also JsonpRequestBuilder works with GET not POST.
How can I achieve those: Sending requests with POST and modifying GWT's default callback name.
JSONP will NOT work with POST. Its not a GWT limitation btw.
JSONP is essentially including a javascript file from your server. So, when you make a JSONP call, a temporary tag is added to the DOM.
Now, a <script> tag can always makes a GET request. That's a browser thing, and GWT cannot do much about it.
If you want to make a cross-domain POST call, you have to chose from one of the following options (and they have nothing to do with GWT)
Use Flash plus a crossdomain.xml that allows cross domain posts
Use Cross Origin Resource Sharing, or CORS. NOTE that this is only supported in modern browsers
Use a proxy server on your domain
Unfortunatly, this isn't how JsonP works. The requests are made by adding a tag to the page, and the results are passed into a function wrapped around the data – in your case, __gwt_jsonp_P0.onSuccess.
The callback name can't be affected, at least while using JsonpRequestBuilder – the system needs to account for the fact that you could send multiple requests out at once, possibly even to different endpoints. A JsonP endpoint that doesn't allow the caller to customize the callback function name is very unusual, and even more odd is an endpoint expecting JsonP calls that expects an impossible POST.
You can implement your own JsonP client side code by using the ScriptElement type, and registering your own global callback to call into your GWT java code.
Look into the API docs for the web service, and see if there is perhaps a better way to communicate with it, perhaps by using a proxy on your own server, avoiding the cross domain issue altogether.