302 Response for session management from ajax request - java

I am trying to manage a user session by making an ajax request to java code repeatedly
function sendSessionKeepAliveRequest() {
$.get('${URL}/sessionKeepAlive?nd=' + new Date().getTime());
}
and java code (spring framework used) handling this request:
#RequestMapping("/sessionKeepAlive")
public String dummySessionKeepAlive(HttpServletResponse response,
HttpServletRequest request) {
PrintWriter writer = null;
try {
writer = response.getWriter();
} catch (IOException e) {
logger.error(e.getMessage());
}
if (writer != null) {
response.setContentType("application/json");
// Sending an empty JSON response.
Gson gson = new Gson();
writer.write(gson.toJson(""));
}
return null;
}
Now the issue is some times were are getting 302 Found instead of 200 OK which makes jsessionid change and session got time out.I have tested in on IE and FF and both of the browser have same behaviour.
Code is deployed on IBM websphere v7.0
Please help or any direction.Please feel free if any more inputs are required or I need to modify my question.
Kind Regards

You have encountered a so-called redirection: The url of the resource you've requested has changed. The new url is provided in the http header 'Location'.
You can either read out this location and issue another Request using this url or you can set up your response handling code to automatically follow the redirection.
Sample code:
function sendSessionKeepAliveRequest() {
$.ajax(
url: '${URL}/sessionKeepAlive?nd=' + new Date().getTime()
, statusCode: {
302: function ( jqXHR, textStatus, errorThrown ) {
var url_trg = jqXHR.getResponseHeader('Location');
$.get(url_trg);
}
}
});
Update
jquery ajax requests should handle 302 status codes automatically, so there might be some other problem. Could it possibly be a cross-domain issue ?

If the purpose is just only to alive session then no need to use GSON you can pass empty String and add one annotation
#ResposeBody
This will help you to get ajax response.

Related

Play framework 2.6 - Java : Ws request POST with oAuth Instagram

I'm trying to communicate with Instagram's API but the reply I get back from my request says that the parameters I passed onto the body weren't detected.
{"error_type":"OAuthException","code":400,"error_message":"You must provide a client_id"}
I tried to send the request by passing a JsonNode or a string inside .post(), like below, but both where unsuccessful.
public CompletionStage<Result> getInstagramToken() {
String code = request().getQueryString("code");
if(code != null) {
WSRequest request = ws.url("https://api.instagram.com/oauth/access_token").setContentType("application/x-wwww-form-urlencoded");
// Json body
/*JsonNode body = Json.newObject()
.put("client_id", insta_clientId)
.put("client_secret", insta_clientSecret)
.put("grant_type", "authorization_code")
.put("redirect_uri", redirect_uri)
.put("code", code);*/
// String body
String body = "client_id="+insta_clientId+"&client_secret="+insta_clientSecret+"&grant_type=authorization_code&redirect_uri="+redirect_uri+"&code="+code;
CompletionStage<WSResponse> response = request.post(body);
return response.thenApplyAsync(resp -> ok(resp.asJson()), exec);
}
return null;
}
The same request passed flawlessly when trying to send it by using a curl command on a terminal or with the Rested plugin on chrome ( where "content type" is set to "application/x-www-form-urlencoded" and the parameters are placed inside "Request body" )
Does anyone have any idea as to how I am supposed to send this request ?
ps: I am also looking for a way to retrieve the value received from my request and store it in a variable instead of returning it to the client.
It seems you are missing a:
.setContentType("application/x-www-form-urlencoded")
Look at our code below. In the post() you can also use a Json object so you can send a HashMap:
CompletionStage<Result> out = ws.url(cbUrl)
.setAuth(<<your user>> , <<your password>>, WSAuthScheme.BASIC)
.setRequestTimeout(Duration.ofSeconds(5))
.setContentType("application/x-www-form-urlencoded")
.post("param=value")
.handle((response, error) -> {
// Was the Chargebee API successful?
if (error == null) {
// Debugging purposes
JsonNode jn = response.asJson();
Logger.debug(Json.toJson(postMap).toString());
Logger.debug(jn.toString());
// Success stuff
return ok("good");
} else {
// Error stuff
return ok("bad");
}
});
Hope this helps you.

Get user groups from MS Azure Active Directory

I am trying to get all the groups a user belongs to. When i run the below code i get 405 error. Am i not calling the resources correctly? Was following: https://msdn.microsoft.com/en-us/library/azure/ad/graph/api/users-operations#GetUsersMemberships
#RequestMapping(value="/groups", method = { RequestMethod.GET, RequestMethod.POST })
public JSONArray getMembersOf(HttpServletRequest httpRequest) {
try {
HttpSession session = httpRequest.getSession();
AuthenticationResult result =
(AuthenticationResult) session.getAttribute(AuthHelper.PRINCIPAL_SESSION_NAME);
String accessToken = result.getAccessToken();
String tenant = session.getServletContext().getInitParameter("tenant");
URL url =
new URL(String.format("https://graph.windows.net/%s/users/userId#abc.onmicrosoft.com/getMemberGroups?api-version=2013-04-05",
tenant, accessToken));
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// Set the appropriate header fields in the request header.
conn.setRequestProperty("api-version", "2013-04-05");
conn.setRequestProperty("Authorization", accessToken);
conn.setRequestProperty("Accept", "application/json;odata=minimalmetadata");
String goodRespStr = HttpClientHelper.getResponseStringFromConn(conn, true);
System.out.println("REsponse is --------------->>>>> "+goodRespStr);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Error:
java.io.IOException: Server returned HTTP response code: 405 for URL: https://graph.windows.net/abc.onmicrosoft.com/users/userId#abc.onmicrosoft.com/getMemberGroups?api-version=2013-04-05
According to your code, based on my understanding, I think you want to get collection that contains the object IDs of the groups of which the user is a member which is the Azure AD REST API Get Member Groups for Users. The error code returned from server seems to means Method Not Allowed which you can refer to the section 10.4.6 405 Method Not Allowed of HTTP RFC doc.
I think the issue might be caused by using an outdated value of api-version, please using 1.6 instread of 2013-04-05 in your code and try again.
Any update, please feel free to let me know.

400 Bad Request!! when I try to send ajax request to Servlet in spring mvc

/*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

File upload along with other object in Jersey restful web service

I want to create an employee information in the system by uploading an image along with employee data. I am able to do it with different rest calls using jersey. But I want to achieve in one rest call.
I provide below the structure. Please help me how to do in this regard.
#POST
#Path("/upload2")
#Consumes({MediaType.MULTIPART_FORM_DATA,MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response uploadFileWithData(
#FormDataParam("file") InputStream fileInputStream,
#FormDataParam("file") FormDataContentDisposition contentDispositionHeader,
Employee emp) {
//..... business login
}
Whenever I am trying to do, I get error in Chrome postman. The simple structure of my Employee json is given below.
{
"Name": "John",
"Age": 23,
"Email": "john#gmail.com",
"Adrs": {
"DoorNo": "12-A",
"Street": "Street-11",
"City": "Bangalore",
"Country": "Karnataka"
}
}
However I can do it by making two different call, but I want to achieve in one rest call so that I can receive the file as well as the actual data of the employee.
Request you to help in this regard.
You can't have two Content-Types (well technically that's what we're doing below, but they are separated with each part of the multipart, but the main type is multipart). That's basically what you are expecting with your method. You are expecting mutlipart and json together as the main media type. The Employee data needs to be part of the multipart. So you can add a #FormDataParam("emp") for the Employee.
#FormDataParam("emp") Employee emp) { ...
Here's the class I used for testing
#Path("/multipart")
public class MultipartResource {
#POST
#Path("/upload2")
#Consumes({MediaType.MULTIPART_FORM_DATA})
public Response uploadFileWithData(
#FormDataParam("file") InputStream fileInputStream,
#FormDataParam("file") FormDataContentDisposition cdh,
#FormDataParam("emp") Employee emp) throws Exception{
Image img = ImageIO.read(fileInputStream);
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(img)));
System.out.println(cdh.getName());
System.out.println(emp);
return Response.ok("Cool Tools!").build();
}
}
First I just tested with the client API to make sure it works
#Test
public void testGetIt() throws Exception {
final Client client = ClientBuilder.newBuilder()
.register(MultiPartFeature.class)
.build();
WebTarget t = client.target(Main.BASE_URI).path("multipart").path("upload2");
FileDataBodyPart filePart = new FileDataBodyPart("file",
new File("stackoverflow.png"));
// UPDATE: just tested again, and the below code is not needed.
// It's redundant. Using the FileDataBodyPart already sets the
// Content-Disposition information
filePart.setContentDisposition(
FormDataContentDisposition.name("file")
.fileName("stackoverflow.png").build());
String empPartJson
= "{"
+ " \"id\": 1234,"
+ " \"name\": \"Peeskillet\""
+ "}";
MultiPart multipartEntity = new FormDataMultiPart()
.field("emp", empPartJson, MediaType.APPLICATION_JSON_TYPE)
.bodyPart(filePart);
Response response = t.request().post(
Entity.entity(multipartEntity, multipartEntity.getMediaType()));
System.out.println(response.getStatus());
System.out.println(response.readEntity(String.class));
response.close();
}
I just created a simple Employee class with an id and name field for testing. This works perfectly fine. It shows the image, prints the content disposition, and prints the Employee object.
I'm not too familiar with Postman, so I saved that testing for last :-)
It appears to work fine also, as you can see the response "Cool Tools". But if we look at the printed Employee data, we'll see that it's null. Which is weird because with the client API it worked fine.
If we look at the Preview window, we'll see the problem
There's no Content-Type header for the emp body part. You can see in the client API I explicitly set it
MultiPart multipartEntity = new FormDataMultiPart()
.field("emp", empPartJson, MediaType.APPLICATION_JSON_TYPE)
.bodyPart(filePart);
So I guess this is really only part of a full answer. Like I said, I am not familiar with Postman So I don't know how to set Content-Types for individual body parts. The image/png for the image was automatically set for me for the image part (I guess it was just determined by the file extension). If you can figure this out, then the problem should be solved. Please, if you find out how to do this, post it as an answer.
See UPDATE below for solution
And just for completeness...
See here for more about MultiPart with Jersey.
Basic configurations:
Dependency:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey2.version}</version>
</dependency>
Client config:
final Client client = ClientBuilder.newBuilder()
.register(MultiPartFeature.class)
.build();
Server config:
// Create JAX-RS application.
final Application application = new ResourceConfig()
.packages("org.glassfish.jersey.examples.multipart")
.register(MultiPartFeature.class);
If you're having problems with the server configuration, one of the following posts might help
What exactly is the ResourceConfig class in Jersey 2?
152 MULTIPART_FORM_DATA: No injection source found for a parameter of type public javax.ws.rs.core.Response
UPDATE
So as you can see from the Postman client, some clients are unable to set individual parts' Content-Type, this includes the browser, in regards to it's default capabilities when using FormData (js).
We can't expect the client to find away around this, so what we can do, is when receiving the data, explicitly set the Content-Type before deserializing. For example
#POST
#Path("upload2")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFileAndJSON(#FormDataParam("emp") FormDataBodyPart jsonPart,
#FormDataParam("file") FormDataBodyPart bodyPart) {
jsonPart.setMediaType(MediaType.APPLICATION_JSON_TYPE);
Employee emp = jsonPart.getValueAs(Employee.class);
}
It's a little extra work to get the POJO, but it is a better solution than forcing the client to try and find it's own solution.
Another option is to use a String parameter and use whatever JSON library you use to deserialze the String to the POJO (like Jackson ObjectMapper). With the previous option, we just let Jersey handle the deserialization, and it will use the same JSON library it uses for all the other JSON endpoints (which might be preferred).
Asides
There is a conversation in these comments that you may be interested in if you are using a different Connector than the default HttpUrlConnection.
You can access the Image File and data from a form using MULTIPART FORM DATA By using the below code.
#POST
#Path("/UpdateProfile")
#Consumes(value={MediaType.APPLICATION_JSON,MediaType.MULTIPART_FORM_DATA})
#Produces(value={MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public Response updateProfile(
#FormDataParam("file") InputStream fileInputStream,
#FormDataParam("file") FormDataContentDisposition contentDispositionHeader,
#FormDataParam("ProfileInfo") String ProfileInfo,
#FormDataParam("registrationId") String registrationId) {
String filePath= "/filepath/"+contentDispositionHeader.getFileName();
OutputStream outputStream = null;
try {
int read = 0;
byte[] bytes = new byte[1024];
outputStream = new FileOutputStream(new File(filePath));
while ((read = fileInputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
outputStream.flush();
outputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch(Exception ex) {}
}
}
}
When I tried #PaulSamsotha's solution with Jersey client 2.21.1, there was 400 error. It worked when I added following in my client code:
MediaType contentType = MediaType.MULTIPART_FORM_DATA_TYPE;
contentType = Boundary.addBoundary(contentType);
Response response = t.request()
.post(Entity.entity(multipartEntity, contentType));
instead of hardcoded MediaType.MULTIPART_FORM_DATA in POST request call.
The reason this is needed is because when you use a different Connector (like Apache) for the Jersey Client, it is unable to alter outbound headers, which is required to add a boundary to the Content-Type. This limitation is explained in the Jersey Client docs. So if you want to use a different Connector, then you need to manually create the boundary.
Your ApplicationConfig should register the MultiPartFeature.class from the glassfish.jersey.media.. so as to enable file upload
#javax.ws.rs.ApplicationPath(ResourcePath.API_ROOT)
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
//register the necessary headers files needed from client
register(CORSConfigurationFilter.class);
//The jackson feature and provider is used for object serialization
//between client and server objects in to a json
register(JacksonFeature.class);
register(JacksonProvider.class);
//Glassfish multipart file uploader feature
register(MultiPartFeature.class);
//inject and registered all resources class using the package
//not to be tempered with
packages("com.flexisaf.safhrms.client.resources");
register(RESTRequestFilter.class);
}
I used file upload example from,
http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey/
in my resource class i have below method
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response attachupload(#FormDataParam("file") byte[] is,
#FormDataParam("file") FormDataContentDisposition fileDetail,
#FormDataParam("fileName") String flename){
attachService.saveAttachment(flename,is);
}
in my attachService.java i have below method
public void saveAttachment(String flename, byte[] is) {
// TODO Auto-generated method stub
attachmentDao.saveAttachment(flename,is);
}
in Dao i have
attach.setData(is);
attach.setFileName(flename);
in my HBM mapping is like
<property name="data" type="binary" >
<column name="data" />
</property>
This working for all type of files like .PDF,.TXT, .PNG etc.,
The request type is multipart/form-data and what you are sending is essentially form fields that go out as bytes with content boundaries separating different form fields.To send an object representation as form field (string), you can send a serialized form from the client that you can then deserialize on the server.
After all no programming environment object is actually ever traveling on the wire. The programming environment on both side are just doing automatic serialization and deserialization that you can also do. That is the cleanest and programming environment quirks free way to do it.
As an example, here is a javascript client posting to a Jersey example service,
submitFile(){
let data = new FormData();
let account = {
"name": "test account",
"location": "Bangalore"
}
data.append('file', this.file);
data.append("accountKey", "44c85e59-afed-4fb2-884d-b3d85b051c44");
data.append("device", "test001");
data.append("account", JSON.stringify(account));
let url = "http://localhost:9090/sensordb/test/file/multipart/upload";
let config = {
headers: {
'Content-Type': 'multipart/form-data'
}
}
axios.post(url, data, config).then(function(data){
console.log('SUCCESS!!');
console.log(data.data);
}).catch(function(){
console.log('FAILURE!!');
});
},
Here the client is sending a file, 2 form fields (strings) and an account object that has been stringified for transport. here is how the form fields look on the wire,
On the server, you can just deserialize the form fields the way you see fit. To finish this trivial example,
#POST
#Path("/file/multipart/upload")
#Consumes({MediaType.MULTIPART_FORM_DATA})
public Response uploadMultiPart(#Context ContainerRequestContext requestContext,
#FormDataParam("file") InputStream fileInputStream,
#FormDataParam("file") FormDataContentDisposition cdh,
#FormDataParam("accountKey") String accountKey,
#FormDataParam("account") String json) {
System.out.println(cdh.getFileName());
System.out.println(cdh.getName());
System.out.println(accountKey);
try {
Account account = Account.deserialize(json);
System.out.println(account.getLocation());
System.out.println(account.getName());
} catch (Exception e) {
e.printStackTrace();
}
return Response.ok().build();
}

XMLHttpRequest Exception 101 when i try to call POST rest with jquery

i'm using jquery ,jersey and json.
when i try to call a post service i receive this error
Origin null is not allowed by Access-Control-Allow-Origin.
undefined * Error: NETWORK_ERR: XMLHttpRequest Exception 101
My client code
$.ajax({url: jurl, type: 'POST', dataType : 'json', headers: {accept:"application/json"},data: inData , cache : false, async : false, contentType : "application/json; charset=utf-8",
My server Code
#POST
#Path(ReferentialPath.PLAYER_RESOURCE_PATH)
#Consumes(MediaType.APPLICATION_JSON)
public Response createPlayer(CreatePlayerIn cPlayer) {
try {
String res = dao.create(player);
UriBuilder ub = uriInf.getAbsolutePathBuilder();
URI createdUri = ub.path(res).build();
return Response.created(createdUri).build();
} catch (Exception e) {
}
}
Would anybody tell me what could be the problem
you seem to be trying to POST to another domain.
possible problem wiki
possible solution :you should read this SO question
Here I guess there must be some firewall between your client and server. HTTP Code 101 represents that your http request be filtered by your net work device. so change your net work and directly connect your server. and try again.

Categories