I'm working on a restlet built on restlet 1.1.1
The issue I'm facing is setting the 'Access-Control-Allow-Origin' header to allow for cross domain requests. I've attempted a few things that didn't work.
Method one, put the header in the acceptRepresentation function:
#Override
public void acceptRepresentation( Representation resetEntity ) {
Form headers = (Form)getResponse().getAttributes().get("org.restlet.http.headers");
if (headers == null) {
headers = new Form();
getResponse().getAttributes().put("org.restlet.http.headers", headers);
}
headers.add("Access-Control-Allow-Origin","https://origin.server.edu");
//other code here for actual resource logic...
}
This didn't work. I still received errors when attempting to send a request using JQuery as such:
jQuery.ajax({
type: "POST",
contentType: "application/json",
url: "https://test.servername.edu/cas/cas-rest-api/reset/",
data: JSON.stringify("{\"uname\" : \"someone\", \"attr\":\"dataElement\" }"),
dataType: "json",
crossDomain: true
})
.done(function(data){
console.log("Success");
alert(data);
})
.fail(function(data){
console.log("failure");
console.log(data);
alert(data);
});
This didn't work. So I noticed an init function in the resource class. I figured I'd attempt putting my code there to see if this would change the situation.
#Override
public void init(Context context, Request request, Response response ){
Form headers = (Form)response.getAttributes().get("org.restlet.http.headers");
if (headers == null) {
headers = new Form();
response.getAttributes().put("org.restlet.http.headers", headers);
}
headers.add("Access-Control-Allow-Origin","https://origin.server.edu");
super.init(context, request, response);
}
Nope. Didn't work either. What am I missing here? Where do I set this header?
Thanks for your replies. After some analysis of the problem it turned out that I needed to configure Spring to allow option requests for my restlet in the web.xml file as shown below:
<servlet>
<servlet-name>ccrest</servlet-name>
<servlet-class>com.noelios.restlet.ext.spring.RestletFrameworkServlet</servlet-class>
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
Related
I am facing an 'HTTP 403 Forbidden' error while trying to consume PUT request of a restful resource from an angular client. I created this restful resource using jersey and I am using tomcat 7 as application server.
Here is my resource code:
#Path("/doc")
public class DocResource {
#PUT
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
#Path("file/upload")
public Response uploadFile(MultipartBody body, #QueryParam("ID") long ID) {
try {
Attachment attachment = body.getAttachment("file");
MultivaluedMap<String, String> headers = attachment.getHeaders();
String fileName = getFileName(headers);
DataHandler dataHandler = attachment.getDataHandler();
InputStream inputStream = dataHandler.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] tmp = new byte[4096];
int ret = 0;
while ((ret = inputStream.read(tmp)) > 0) {
bos.write(tmp, 0, ret);
}
// TODO - Save contents as process attachment
byte[] contents = bos.toByteArray();
return Response.ok(getDocumentService().createAttachment(ID, fileName, contents, attachment.getContentType()), MediaType.APPLICATION_JSON).build();
} catch (Exception e) {
return handleException(e, "failed to upload Attachement");
}
}
}
Here is my angular js snippet
this.uploadFile = function uploadFile(callback, ID, file) {
var baseRestURL="http://localhost:8080/rest/doc"
// resource query
var query ;
// create form data
var formData = new FormData();
formData.append('file', file);
// set up the resource
var resource = $resource(baseRestURL + '/file/upload', {
ID: ID
}, {
'ID': ID,
'upload': {
method: 'PUT',
headers: {
'Content-Type': 'multipart/form-data'
}
}
});
resource.upload(query, formData).$promise.then(function success(response) {
if (callback) callback(response);
}, function error() {
//TODO handle error
});
};
I want to notice that other type of http calls such as DELETE, POST and GET are working properly. I have only problems with PUT calls.
I had a similar issue, but both DELETE and PUT were not working for me - returned HTTP 403 error. After I searched I stumbled across this link, and it pointed out where I went wrong.
I had a CORS filter added in my web.xml as part of some other R&D i was doing, and forgot to remove it.
This was from the original web.xml
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.jaxrs.listing,
com.xxx.yyy.rest</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
org.glassfish.jersey.jackson.JacksonFeature;
org.apache.catalina.filters.CorsFilter
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Once I removed the org.apache.catalina.filters.CorsFilter it started to work for me!
Hope this helps!
I'm trying to post data from Angular to my servlet. But, it throws me the error
"Failed to load resource: the server responded with a status of 405 (Method Not Allowed)"
Here is my code. Am I missing anything?
$scope.pushDataToServer = function() {
$scope.data = {user_id:"123",key_name:"key2",value:"value2"};
$http({
method: 'POST',
url: 'pushData',
headers: {'Content-Type': 'application/json'},
data: $scope.data
}).success(function (data){
$scope.status=data;
}).error(function(data, status, headers, config) {
alert("error")
});
};
My servlet config
<servlet>
<servlet-name>pushData</servlet-name>
<servlet-class>com.data.pushData</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pushData</servlet-name>
<url-pattern>/pushData</url-pattern>
</servlet-mapping>
write a do post method in your servlet.
/**
* handles HTTP POST request
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
//TODO: handle POST here
}
Simple, the servlet you are calling doesn't support the POST method.
You haven't implemented it or has done so erroneously.
I´m trying to use DeferredResult with an ajax request, but when I return the result my ajax request keeps waiting for response.
Here the client that make the long polling request
(function poll() {
var SUCCESS = 1;
var tenantName = $("#tenantName").val();
$.ajax({
method: "GET",
url: "url.do?subStep=" + subStep + "&tenantId=" + tenantName,
success: function (response) {
alert(response)
if (response.status === SUCCESS) {
bootbox.dialog({
size:"small",
message: "<div class='col-xs-offset-4'>" +
"<i class='fa fa-user'> Page has been modify by " + response.payload + " " +
"<a href='javascript:void(0)' onclick='reload()'>reload</a>" +
"</i>" +
"</div>"
});
}
}, dataType: "json", complete: poll, timeout: 60000
});
})();
Here my controller where I make a long polling request by Ajax every 30 seconds.
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public DeferredResult<JsonEntity> getSubStepStatus(#RequestParam("subStep") String subStep,
#RequestParam("tenantId") String tenantId) {
if (tenantsInStep.get(subStep) == null) {
initializeTenantsInStep(subStep);
}
if(!tenantsInStep.get(subStep).contains(tenantId)){
tenantsInStep.get(subStep).add(tenantId);
}
DeferredResult<JsonEntity> deferredResult = new DeferredResult<>();
tenantsDeferredInStep.put(tenantId, deferredResult);
return deferredResult;
}
And then when my application detect a POST/PUT ajax request invoke a request to this method of my controller that release the DeferredResults.
#RequestMapping(value = "/setModification", method = RequestMethod.GET)
#ResponseBody
public final Integer setModification(#RequestParam("subStep") String subStep,
#RequestParam("tenantId") String tenantId) {
for (String tenantInStepId : tenantsInStep.get(subStep)) {
if (!tenantId.equals(tenantInStepId)) {
JsonEntity<String> jsonEntity = new JsonEntity();
jsonEntity.setPayload(tenantId);
jsonEntity.setStatus(FeedbackActions.SUCCESS.getCode());
DeferredResult<JsonEntity> jsonEntityDeferredResult = tenantsDeferredInStep.get(tenantId);
tenantsInStep.remove(tenantInStepId);
jsonEntityDeferredResult.setResult(jsonEntity);
}
}
return FeedbackActions.SUCCESS.getCode();
}
This example has been done by two user with two browser to achieve this, but the first client that create the deferredResult dont receive the result when the second client invoke the deferredResult.setResult(bla), no alert on ajax code is invoked.
I´m doing something wrong?, I add the
<task:annotation-driven/>
And the
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
In my applicationContext and web.xml configuration
As an extra information I´m using on my local test Jetty
Regards.
/*ajax request to servlet to perform update operation*/
var savedata={
video_Title:videotitle,
video_duration:videoduration,
video_Url:videourl,
video_Description:videodescription
};
$.ajax({
url:'videoUpdate',
type:'POST',
cache:false,
data: savedata,
contentType: "application/json; charset=utf-8",
success: function(response) {
alert("Updated Successfully");
},
error:function()
{
alert("oops sorry something went wrong. we apologize for the inconvenience");
}
});
/*Controller Class*/
#RequestMapping(value ="videoUpdate",method = RequestMethod.POST,consumes=MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody Status updateVideo(#RequestBody Video video) {
try {
System.out.println("update servlet");
dataServices.updateVideo(video);
return new Status(1,"video updated Successfully");
}
catch (Exception e) {
return new Status(0,e.getMessage().toString());
}
}
My question is how to receive ajax-json request data in my servlet class.Is this is the correct way to catch a set of data from ajax in spring mvc.Or other annotation is required for avoiding 400 error!?
The 400 Bad Request seldom happens because the url viz videoUpdate could not be mapped to appropriate mapping.
This could be because you might not be passing the arguments required to make to point cut.
I would suggest you to inspect following portion of your code:
var savedata={
video_Title:videotitle,
video_duration:videoduration,
video_Url:videourl,
video_Description:videodescription
};
And make sure you are passing required parameters.
If you specify
contentType: "application/json; charset=utf-8",
that means you are expecting JSON data in return - if it's not valid JSON then it goes to the error block.
You are probably returning a string :
return new Status(0,e.getMessage().toString());
Try omitting the contentType line. Also posting browser console errors might help us determine the problem easier.
Note: If you want to specify the outgoing data type there's a dataType setting.
Assuming the URL you are hitting is correct, you could look at whether the fields of the Video class exactly match the JSON you are POSTing
I'm trying to call a Webservice that consumes a json object with post method .I did it then It wont work again don't know what is the problem.
here is my method
#POST
#Path("/post")
#Consumes("application/json")
#Produces("application/json")
public Response testClient(Client c) throws IOException {
System.out.println(c.getAdresseCl());
ResponseBuilder builder = Response.ok(c.getAdresseCl());
builder.header("Access-Control-Allow-Origin", "*");
builder.header("Access-Control-Max-Age", "3600");
builder.header("Access-Control-Allow-Methods", "*");
builder.header(
"Access-Control-Allow-Headers",
"X-Requested-With,Host,User-Agent,Accept,Accept-Language,Accept-Encoding,Accept-Charset,Keep-Alive,Connection,Referer,Origin");
return builder.build();
}
to call this I used this
$.ajax({
type: 'POST',
url: "http://localhost:9080/FournisseurWeb/jaxrs/clients/post",
data: '{"adresseCl":"tunis"}',
dataType:'json',
contentType: "application/json; charset=utf-8",
success: function (msg) {
alert(msg);
},
error: function (xhr, ajaxOptions, thrownError) {
alert('error');
}
});
well I remark that when I set the contentType to application/json the method changes to OPTIONS .
and when I don't use the content type I got "415 Unsupported Media Type " I dont know how to fix this. I passed too much time without results :(thank you for helping me
When attempting to make cross-domain AJAX requests in certain browsers, it is a common to see the HTTP Method change to OPTIONS in lieu of a more meaningful error message.
I noticed in your URL that you're including the protocol, domain, and port, which supports the theory that you're actually trying to make an AJAX request to a different domain/port combination than the originating context.
To clarify, even if your request is originating from localhost and targeting localhost, the ports (9080) and protocols (http) must also match.
Thus, if the page you loaded is "http://localhost:8080" and you're trying to make an AJAX request to "http://localhost:9080", the request will fail, may throw same-domain security errors, 415 Unsupported Media Type, and/or change the HTTP Method to OPTIONS.
One way to make sure you avoid this mistake is to only use full or relative paths when making AJAX requests, such as:
url: "/FournisseurWeb/jaxrs/clients/post",
This forces you to always make requests to the same domain.
Cross-domain Requests
If you do indeed require the ability to make cross-domain requests, this is possible, but only through two methods.
First, you can use a proxy, where you make an HTTP request to your domain and then forward the request onto another server. Servers need not be concerned with same-domain policies when sending and receiving data from one another.
Second, you can use JSONP, also known as script tag remoting, which involves exploiting the <script> element's ability to send requests across different domains.
// added callback= query parameter to convert this to JSONP
$.ajax({
type: 'POST',
url: "http://localhost:9080/FournisseurWeb/jaxrs/clients/post?callback=",
data: '{"adresseCl":"tunis"}',
dataType:'json',
contentType: "application/json; charset=utf-8",
success: function (msg) {
alert(msg);
},
error: function (xhr, ajaxOptions, thrownError) {
alert('error');
}
});
NOTE: When using JSONP, your server must respond with the JSON wrapped up in a function call identified by the callback parameter. See the jQuery documentation for more in-depth details .
Other than that, you must make AJAX requests to the same domain the page was loaded from.
this is the method that consumes a text xml fomat and map it to an object to persist it next
#POST
#Path("/inscription")
#Produces(MediaType.TEXT_HTML)
public Response testClient(String s) {
ResponseBuilder builder = null;
try {
final String xmlString = s;
final StringReader xmlReader = new StringReader(xmlString);
final StreamSource xmlSource = new StreamSource(xmlReader);
final JAXBContext jaxbContext = JAXBContext
.newInstance(Client.class);
final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
final Client client = (Client) unmarshaller.unmarshal(xmlSource,
Client.class).getValue();
System.out.println("nomCl : " + client.getNomCl());
System.out.println("prenomCl : " + client.getPrenomCl());
System.out.println("emailCl : " + client.getEmailCl());
System.out.println("numTel : " + client.getNumTel());
System.out.println("long_ : " + client.getLong_());
System.out.println("lat : " + client.getLat());
System.out.println("LoginCl : " + client.getLoginCl());
System.out.println("PasswordCl : " + client.getPasswordCl());
System.out.println("adresseCl : " + client.getAdresseCl());
EntityManagerFactory factory;
factory = Persistence.createEntityManagerFactory("FournisseurWeb");
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
em.persist(client);
em.getTransaction().commit();
em.close();
factory.close();
builder = Response.ok("true");
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
builder = Response.ok("false");
builder.header("Access-Control-Allow-Origin", "*");
builder.header("Access-Control-Max-Age", "3600");
builder.header("Access-Control-Allow-Methods", "POST");
builder.header(
"Access-Control-Allow-Headers",
"X-Requested-With,Host,User-Agent,Accept,Accept-Language,Accept-Encoding,Accept-Charset,Keep-Alive,Connection,Referer,Origin");
return builder.build();
}
builder.header("Access-Control-Allow-Origin", "*");
builder.header("Access-Control-Max-Age", "3600");
builder.header("Access-Control-Allow-Methods", "POST");
builder.header(
"Access-Control-Allow-Headers",
"X-Requested-With,Host,User-Agent,Accept,Accept-Language,Accept-Encoding,Accept-Charset,Keep-Alive,Connection,Referer,Origin");
return builder.build();
}
I use to call this method using ajax with this sample :
var x="<client><nomCl>Taarit</nomCl><prenomCl>Aymen</prenomCl><emailCl>aymen.taarit#gmail.com</emailCl><numTel>222</numTel><long_>1.66</long_></client>";
$.ajax({
url: 'http://localhost:9080/FournisseurWeb/jaxrs/clients/cl',
type: 'post',
scriptCharset: "utf-8" ,
dataType:"xml",
data: x,
success: function(data, status) {
console.log(data);
}
});
this is a jax-rs call with ajax POST using cross domain so hope that it helps :)
NOTE: The cross-domain call without JSONP is legal here because the server is returning the following header, which enables cross-domain AJAX!
builder.header("Access-Control-Allow-Origin", "*");
See Mozilla Developer Center page on Access-Control-Allow-Origin for more details.