My app suppose to download file from DB.
Controller:
#GetMapping(value = "/download/{id}")
public ResponseEntity<Resource> downloadBook(#PathVariable Long id) {
Book book = bookService.findById(id);
return ResponseEntity.ok().contentType(MediaType.APPLICATION_PDF)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + book.getFileName() + ".pdf\"")
.body(new ByteArrayResource(book.getFile()));
}
This works when i call it directly from browser (download pop up), but what i'm tring to do is handle it with ajax call. This is my ajax method so far, but this code actually just alert me with success with no dowload pop up.
downloadBook : function(bookId) {
$.ajax({
url : basePath + '/book/download/' + bookId,
success : function() {
alert("success!");
},
error : function() {
alert("error!");
}
});
}
See Download a file by jQuery.Ajax
What's happening here is that your ajax request is being made to /book/download/ as specified in the url: parameter. When the request completes successfully it fires the success callback. However, all you are doing there is showing an alert - with alert("success!") - so nothing further will happen.
The linked answer explains why you cannot simply do this with ajax like you might imagine. I haven't reiterated all of the linked answer as it's already been explained there, but the principal of that answer is exactly the same for your problem.
downloadBook : function(bookId) {
window.location = basePath + '/book/download/' + bookId
}
My downloadBook method looks like this now and it solved my problem.
Related
Situation:
I have a jsp within a jsp. I load another jsp into a div of the outer jsp using .html(). I want to redirect my url into an entirely new url mapping from a controller.
Sample controller:
#RequestMapping(value = { "/main/submit" }, method = RequestMethod.POST)
public String main(ModelMap model) {
System.out.println("In controller");
return "redirect:/anotherJSP";
}
#RequestMapping(value = { "/anotherJSP" }, method = RequestMethod.POST)
public String anotherJSP(ModelMap model) {
System.out.println("In another");
return "anotherJSP";
}
Jsp within a jsp:
$.ajax({
type : "POST",
url : "/main/submit",
success : function(msg) {
console.log('redirect');
},
error : function() {
alert("Error.");
}
});
Now, the problem is that the outer jsp stays, and the /anotherJSP url only gets loaded in the innerJSP. I wanted to leave the two jsps and go to the new request mapping URL. Is there anyway I can do it? Thanks a lot in advance!
You can't redirect a POST.
When you return redirect:/anotherJSP, the server sends a redirect instruction back to the web browser, and the browser then sends a new GET request for the given URL.
The GET request will be for the URL given, with any query parameters. This means that and POST payload (data) will be lost.
Change #RequestMapping(value = { "/anotherJSP" }, method = RequestMethod.POST) to #GetMapping("/anotherJSP") (assuming Spring 4.3 or later).
Since an ajax call is asynchronous the effect of return "redirect:/anotherJSP"; is not affecting the browser window, instead you should use window.location.href in your ajax call like this:
$.ajax({
type : "POST",
url : "/main/submit",
success : function(msg) {
console.log('redirect');
window.location.href = /anotherJSP;
},
error : function() {
alert("Error.");
}
});
I have a webpage that fills a datagrid with post ajax requests like this
$.ajax({
type: "POST",
url: "http://bss.bimser.com.tr/Handlers/eBADataGridHandler.ashx",
data: '{"ID":"dgSearchTickets","Type":0,"Page":"2","FilterInput":[],"QuickFilterText":null,"SortedColumn":""}',
success: function(msg){
console.log(msg);
}
});
When i try this with the below code i cant get html result; my code;
webClient.getOptions().setJavaScriptEnabled(true);
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
UnexpectedPage upage = webClient.getPage(webRequestPost);
HtmlPage page = HTMLParser.parseHtml(upage.getWebResponse(), webClient.getCurrentWindow());
WebRequest webRequestPost2 = new WebRequest(new URL(".../DataGridHandler.ashx"), HttpMethod.POST);
webRequestPost2.setAdditionalHeader("Content-Type", "application/x-www-form-urlencoded");
webRequestPost2.setRequestBody(DefaultValues.searchPagingJson2);
page = webClient.getPage(webRequestPost2);
this code returns an error webpage. How can i get html info ?
EDIT:
page.executeJavaScript("var request = new XMLHttpRequest();\n" +
"request.open('POST', 'http://bss.bimser.com.tr/Handlers/eBADataGridHandler.ashx', true);\n" +
"request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n" +
"request.onload = function() {\n" +
" document.getElementsByTagName(\"body\")[0].innerHTML = request.responseText;\n" +
" console.log(request.responseText);\n" +
"};\n" +
"request.send('{\"ID\":\"dgSearchTickets\",\"Type\":0,\"Page\":\"%s\",\"FilterInput\":[],\"QuickFilterText\":null,\"SortedColumn\":\"Sent Date\"}');\n");
I was able to solve the problem by executing the code above. Now the problem is without manual waiting htmlunit does not wait for the result. I tried this below
WebClient webClient = new WebClient(BrowserVersion.FIREFOX_52);
webClient.getOptions().setJavaScriptEnabled(true);
webClient.setAjaxController(new AjaxController() {
#Override
public boolean processSynchron(HtmlPage page, WebRequest request, boolean async) {
return true;
}
});
In general HtmlUnit can do ajax requests.
Creating you own web request is not the design idea of HtmlUnit. Think about HtmlUnit more like a browser automated by your code. Have a look at the samples on the HtmlUnit homepage.
If you really like to create your own requests you are responsible for the whole request. This includes various headers for security or session information. Install a web proxy like Chares and watch the communication of the real page. Then you might be able to create a similar request. And have a look at the returning webpage maybe there is a hint for you (like the login is missing).
I have a problem in my spring boot app with the csrf token.
I have a form where I can edit a Person. A Person can have
Let us now imagine that the person has a car and enter this and store it. The next time he wants to delete this car and enter another one. I have created that so that there is a list of all of his cars -- he has the option to remove this from the list. Now I'm starting from these pills and want to send with the corresponding ID to the server a POST. When I try I get a 403 forbidden and I have no idea why.
If I change from POST to GET, then it works.
My JavaScript (taken from this site: http://docs.spring.io/autorepo/docs/spring-security/4.0.0.CI-SNAPSHOT/reference/htmlsingle/#the-csrfmetatags-tag)
var csrfParameter = $("meta[name='_csrf_parameter']").attr("content");
var csrfHeader = $("meta[name='_csrf_header']").attr("content");
var csrfToken = $("meta[name='_csrf']").attr("content");
// using JQuery to send a non-x-www-form-urlencoded request
var headers = {};
headers[csrfHeader] = csrfToken;
$.ajax({
url: "./delete/car",
type: "GET",
headers: headers,
});
$.ajax({
url: "./delete/car",
type: "POST",
headers: headers,
});
My controller methods:
#RequestMapping(value = "/{login}/delete/car", method = RequestMethod.GET)
public ModelAndView delete(#PathVariable("login") final String login) {
System.out.println("Stop");
return new ModelAndView("redirect:" + WebSecurityConfig.URL_PERSONS_OVERVIEW);
}
#RequestMapping(value = "/{login}/delete/car", method = RequestMethod.POST)
public ModelAndView deleteInstEmp(#PathVariable("login") final String login) {
System.out.println("Stop");
return new ModelAndView("redirect:" + WebSecurityConfig.URL_PERSONS_OVERVIEW);
}
Any suggestions?
Thanks in advance.
OK, after strugglin with all that, I get the following result.
I added the fail method to the Ajax construct and get the following message:
"Failed to execute 'setRequestHeader' on 'XMLHttpRequest': '${_csrf.headerName}' is not a valid HTTP header field name."
the official spring site advises that you have to put this: <sec:csrfMetaTags /> or from other sources, this: <meta name="_csrf" th:content="${_csrf.token}"/> in your html file.
After this, you should be able to access these attributes in your JavaScript, but in my case I get undefined and ${_csrf.headerName}.
A last try was to take the value from the hidden value (chapter 24.5: http://docs.spring.io/autorepo/docs/spring-security/4.0.0.CI-SNAPSHOT/reference/htmlsingle/#the-csrfmetatags-tag).
Now, I have the following:
$(function () {
var token = $("input[name='_csrf']").val();
var header = "X-CSRF-TOKEN";
$(document).ajaxSend(function(e, xhr, options) {
xhr.setRequestHeader(header, token);
});
});
$.ajax({
url: "./delete/car",
type: "POST",
success:function(response) {
alert(response);
}
});
With this it works like a charm.
Another way, you can use the following code:
$.ajax({
url : './delete/car',
headers: {"X-CSRF-TOKEN": $("input[name='_csrf']").val()},
type : 'POST',
success : function(result) {
alert(result.msgDetail);
}
})
I suggest you first check if a valid csrf token and the header have been generated using chrome debugger. If not, then have you added the <sec:csrfMetaTags /> in the <head>?(you will need to import the spring security taglibs). If using Apache tiles, you will have to add this at the <head> section of the template file being used for the view.
If the token is not empty, then in your security-context/configuration file, check if you have disabled csrf security by any chance. By default it is enabled and needs to be for this process to work.
I am using Jquerys Ajax method to talk to my web service. The code seems OK, but I just monitored HTTP traffic using HTTPFox firefox plugin and I noticed unexpected results. To begin with, I am setting the ContentType as application/json and my web service is also producing JSON data but HTTPFox indicates Content Type for my HTTP requests as application/vnd.sun.wadl+xml (NS_ERROR_DOM_BAD_URI).
The Request Method is GET as set in my Ajax request, but HTTPFox indicates my Request method as OPTIONS. And while the Request succeeds and data is returned, the onSuccess method of my Ajax request is not called. Instead, the onError method is called. HTTP Fox is able to capture the data from my web service as response. See the image for HTTP Fox.
Finally, all other request from other processes in my browser seem OK but my HTTP requests are flagged 'RED' by HTTP Fox. The request from other pages and processes seem OK.( GREEN or WHITE).
I have attached screenshot of HTTPFox highlighted on one of my Request. The flagged ones are also from my application.
Image:
I have also pasted the Ajax code I am using to make the HTTP Requests.
window.onload = function() {
var seq_no = getParameterByName("seq_no");
var mileage = getParameterByName("mileage");
document.getElementById("seq_no").value = seq_no;
document.getElementById("mileage").value = mileage;
var param = 'vehReg='+encodeURIComponent(document.getElementById('vehReg').value);
// alert(param);
loadVehicleInfo(param);
};
function loadVehicleInfo(params) {
$("#message").html('<p><font color="green">Loading...</font></p>');
$.ajax({
type: "GET",
url: "http://localhost:8080/stockcloud/rest/vehicles/info",
data: params,
contentType: "application/json; charset=utf-8",
dataType: "json",
success:
function(data,status) {
$("#message").empty();
$("#message").html('<p>'+getAsUriParameters(data)+'</p>');
},
error :
function(XMLHttpRequest, textStatus, errorThrown) {
$("#message").html("<p> <font color='red'>The following error occurred: " +textStatus+ ': '+errorThrown+ "</font>");
}
});
};
function getAsUriParameters (data) {
return Object.keys(data).map(function (k) {
if (_.isArray(data[k])) {
var keyE = encodeURIComponent(k + '[]');
return data[k].map(function (subData) {
return keyE + '=' + encodeURIComponent(subData);
}).join('&');
} else {
return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]);
}
}).join('&');
};
function getParameterByName(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
Server side Code for the request:
#Path("/vehicles")
public class VehiclesService {
#GET
#Path("info")
#Produces("application/json")
public Response getVehicleInfo(#DefaultValue("__DEFAULT__") #QueryParam("vehReg") String vehReg) {
// Send SOAP Message to SOAP Server
ServerResponse resp = new ServerResponse();
if("__DEFAULT__".equals(vehReg)) {
resp.setError("Vehicle registration must be supplied as a query parameter: ?vehReg=<THE REG NO>");
resp.setResult(false);
Response.status(Response.Status.BAD_REQUEST).entity(resp).build();
}
try {
// actual code to return the car info and return XML string with the info.
connection.disconnect();
String xml = URLDecoder.decode(s.toString(),"UTF-8");
xml = xml.replace("<", "<").replace(">", ">").replace("<?xml version='1.0' standalone='yes' ?>", "");
System.out.println(xml);
resp.setVehicle(new VehicleParse().parse(xml));
resp.setResult(true);
} catch(Exception e) {
resp.setResult(false);
resp.setError(e.getMessage());
e.printStackTrace();
Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(resp).build();
}
return Response.status(Response.Status.OK).entity(resp).build();
}
}
Is there something I am not doing right?
Thanks.
I have a servlet that adds a user to a file on the server side.
I invoke it with a jqueries ajax call.
I can see on the server that the method is being called correctly and my user is added, but the error callback is being invoked on the jquery call. All the status text says is error.
Using firebug the response seems to be empty. Why can I not get a success jquery callback?
//Servlet Code
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("action");
String responseStr = "";
if(action.equals("addUser"))
{
responseStr = addUser(request);
}
System.out.println("Reponse:" + responseStr);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().println(responseStr);
}
private String addUser(HttpServletRequest request) throws IOException
{
Storage s;
s = Storage.load();
String name = request.getParameter("name");
String imageUrl = request.getParameter("imageUrl");
User u = new User();
u.setName(name);
u.setImageUrl(imageUrl);
s.addUser(u);
s.save();
return "success";
}
.
//javascript code
function addUser() {
var name = $('#name').val();
var imageUrl = $('#imageUrl').val();
var url = "http://ws06525:8080/QCHounds/QCHoundServlet?action=addUser&name=${name}&imageUrl=${imageUrl}";
url = url.replace("${name}", name);
url = url.replace("${imageUrl}", imageUrl);
$('#result').html(url);
$.ajax({
url: url,
success: function( data ) {
$('#result').html(data);
},
error: function(jqXHR, textStatus, errorThrown)
{
alert("error: " + textStatus);
alert("error: " + errorThrown);
}
});
}
Aaargh! Feel like an idiot. It's a cross site scripting issue.
I was testing the call to the server from the html file on disk so my browser address was
file://projects/myproject/content/Users.html <<< Fail
instead of:
http://myboxname:8080/appname/Users.html <<< Works
The actual code is fine...
use this for learn what is the problem, it will be better for get solution i think
error: function(e){
alert(JSON.stringify(e))
}
For one thing the string "success" isn't valid json. If your ajax query is expecting json, that would fail it.
What if you returned "{ \"success\": true }" ?
EDIT
It looks like from your ajax call that the response shouldn't be json, why is your return content type json?
If it is true that firebug shows no response, your problem must be in the java code that writes the response.