I am working with ajax and node js for the first time. When I use the client to get response from node js it gets into the error function. On the other hand, when I directly call the url from the browser, I get the correct response from the server. This is an indication that something is wrong with the client side ajax request.
This is my client code :
function fetch() {
$.ajax({
type: 'POST',
url: "http://127.0.0.1:8888",
data: {data : 'India'},
dataType: 'json',
success: function () {
alert("hi");
//var ret = jQuery.parseJSON(data);
//$('#q').html(ret.msg);
},
error: function (jqXHR, textStatus, error) {
console.log('Error: ' + error.message);
alert("ERROR");
}
});
This is the server node.js code (part of it). The console.log msg get the correct values.
http.createServer(function(req, response) {
console.log("Request received");
response.writeHeader(200, {"Content-Type": "application/json"});
req.on('data', function (chunk) {
console.log(chunk.toString('utf8'));
console.log(result[0].name);
});
response.end(JSON.stringify({data:result}));
}).listen(8888);
All the console.log in the server gets the correct values. That means the response is not reaching back when there is ajax request, but on directly writing 127.0.0.1:8888, I get correct response.
The message on the console is :
XMLHttpRequest cannot load http://127.0.0.1:8888/. Origin null is not allowed by Access-Control-Allow-Origin.
Please someone help to fix this out. I have been on this for a day now.
EDIT : Screen capture of the network tab. As you can see the server gets the request but the client does not get the response. This is done even after writing 'Access-Control-Allow-Origin' : '*'.
This is the Same Origin Policy. You need to supply the HTML document hosting the JavaScript over HTTP (and, unless you are using CORS, from the same hostname and port as the resource you are requesting with Ajax).
Related
I would like to set up my express server such that I can get the browser to prompt the user to download a JSON file when I send an Ajax GET request. I am able to get the file to download when I request a test route from the browser bar, but when I send the request from Ajax, it won't download, though the request returns 200 and I can see the contents of the file when I look in dev tools.
In the process of trying to get it to work, I thought maybe Express's res.download() function required a GET request, so I set it up so that the first request is a POST that sends the JSON data and gets the filename back, and then sends the filename as a parameter in the GET request.
Any help is greatly appreciated and I would be happy to provide more information if necessary.
Here is the code for the download route:
app.get("/generated-files/download/:file", function(req, res){
const fileName = req.params.file;
console.log(fileName);
const filepath = path.join(__dirname, 'generated-files', fileName);
res.download(filepath, fileName, function(err){
if(err){
console.log(err);
}
/*
fs.unlink(filepath, function(err){
if(err){
console.log(err);
}
});*/
});
});
Here is the test route:
app.get("/download-test", function(req, res){
res.download(path.join(__dirname, 'generated-files', '01a6cbe0-ce2d-11ea-86bc-092eb628bcba.json'), '01a6cbe0-ce2d-11ea-86bc-092eb628bcba.json');
});
And here is the Ajax request:
//begin first ajax request
$.ajax({
contentType: 'application/json',
data: JSON.stringify(serializedCharacter),
success: function(ret){
console.log("Response Received:");
console.log(typeof ret + ":" + ret);
// begin second ajax request
$.ajax({
method: 'GET',
url: '/generated-files/download/' + ret,
success: function (ret){
console.log("delete successful");
},
error: function (jqxhr, ts, err){
console.log("something is wrong in delete");
console.log(jqxhr);
console.log("\n"+ts);
console.log("\n"+err);
}
});
// end second ajax request
},
error: function(jqxhr, textStatus, errorThrown){
console.log("Something is not right");
console.log(jqxhr);
console.log("\n"+textStatus);
console.log("\n"+errorThrown);
},
method: 'POST',
url: '/generated-files'
});
//end first ajax request
EDIT:
OK, so I figured something out. I replaced the second Ajax request with this line:
document.location.href = '/generated-files/download/'+ret;
I suspect the problem was the Accept request header. The default Ajax Accept header is */*, while both the browser bar and aforementioned line had an Accept header of text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8. I may be wrong, in fact I am doubting this somewhat because I was under the impression that */* was supposed signal that the requestor would accept a response of any content type. If anyone could confirm this, or tell me why I am wrong, I would appreciate it greatly.
Ajax purpose is updating a part of web page without reloading the page, using the response data provided by server side app as json or xml. Here the response data will come back to the page itself, and can be used to render the page contents.
In downloading and page redirection the control goes out of the page. So this is
not an Ajax use case.We can achieve those directly using plain javascript as you mentioned in the final section of your description.
For downloading the file your approach is correct by using
document.location.href= url
alternatively we can use
window.location = url
For page redirection we can achieve by
window.location.href = url
QUESTION:
How to check if a url is valid and actually loads a page ?
With my current code, only the status code is checked, which means that a url like http://fsd.com/ will be considered as valid although it does not load anything.
How can I check that the url actually points to a website that can be loaded ?
CODE:
$.ajax({
url: link,
dataType: 'jsonp',
statusCode: {
200: function() {
console.log( "status code 200 returned");
validURL = true;
},
404: function() {
console.log( "status code 404 returned");
validURL = false;
}
},
error:function(){
console.log("Error");
}
});
EDIT: By valid, I mean that the page is at last partially loaded (as in at least the html & css are loaded) instead of loading forever or somehow failing without the status code being 404.
EDIT2: http://fsd.com actually returns a 404 now as it should...
EDIT3: Another example: https://dsd.com loads an empty page (status code 200) and http://dsd.com actually loads a page with content (status code 200). On my Node.js backend, the npm package "url-exists" indicates that https://dsd.com is invalid, while my frontend with the code shown in my question indicates it is a valid url. This is what the package code looks like: https://github.com/boblauer/url-exists/blob/master/index.js but I wanted to know what would be the best way according to SO users.
EDIT4:
Sadly, the request provided by Addis is apparently blocked by CORS which blocks the execution of the rest of my code while my original request did not.
$.ajax({
type: "HEAD",
url: link,
dataType: 'jsonp',
}).done(function(message,text,response){
const size = response.getResponseHeader('Content-Length');
const status = response.status;
console.log("SIZE: "+size);
console.log("STATUS: "+status);
if(size > 0 && status == "200") {
$("#submitErrorMessage").css("display","none");
$('#directoryForm').submit();
}
else {
$("#submitErrorMessage").css("display","block");
$("#submitLoading").css("display","none");
}
});
EDIT 5:
To be more precise, both requests trigger a warning message in the browser console indicating that the response has been blocked because of CORS but my original code is actually executed in its entirety while the the other request doesn't get to the console.log().
EDIT 6:
$.ajax({
async: true,
url: link,
dataType: 'jsonp',
success: function( data, status, jqxhr ){
console.log( "Response data received: ", data );
console.log("Response data length: ", data.length);
console.log("Response status code: ", status);
if (status == "200" && data.length > 0) {
$("#submitErrorMessage").css("display","none");
$('#directoryForm').submit();
}
else {
$("#submitErrorMessage").css("display","block");
$("#submitLoading").css("display","none");
}
},
error:function(jqXHR, textStatus, errorThrown){
console.log("Error: ", errorThrown);
}
});
Error:
Error: Error: jQuery34108117853955031047_1582059896271 was not called
at Function.error (jquery.js:2)
at e.converters.script json (jquery.js:2)
at jquery.js:2
at l (jquery.js:2)
at HTMLScriptElement.i (jquery.js:2)
at HTMLScriptElement.dispatch (jquery.js:2)
at HTMLScriptElement.v.handle (jquery.js:2)
A successful response without content "should" return a 204: No Content but it doesn't mean that every developer implements the spec correctly. I guess it really depends on what you consider "valid" to mean for your business case.
Valid = 200 && body has some content?
If so you can the test this in the success callback.
$.ajax({
url: link,
dataType: 'jsonp',
success: function (response) {
// todo: test the response for "valid"
// proper length? contains expected content?
},
statusCode: {
200: function() {
console.log( "status code 200 returned");
validURL = true;
},
404: function() {
console.log( "status code 404 returned");
validURL = false;
}
},
error:function(){
console.log("Error");
}
});
I think the word "valid" is used a bit wrongly here. Looking at the code snippet, I can see that you are using HTTP error codes to decide whether the URL is valid or not. However, based on the description, it is clear that you consider the resource (pointed by the URL) to be valid only if it is a web page. I would like to urge the fact that HTTP can be used to access resources which need not have a web page representation.
I think you need to go a bit deeper and retrieve that info (whether it is a web-page representation) from the HTTP response that you receive and just relying on the status code would be misleading for you. One clear indicator would be looking at the response header for content-type: text/html.
Sample response from accessing www.google.com:
date: Tue, 18 Feb 2020 17:51:12 GMT
expires: -1
cache-control: private, max-age=0
content-type: text/html; charset=UTF-8
strict-transport-security: max-age=31536000
content-encoding: br
server: gws
content-length: 58083
x-xss-protection: 0
The HEAD request is used to get meta-information contained in the HTTP headers. The good thing is that the response doesn't contain the body. It's pretty speedy and there shouldn't be any heavy processing going on in the server to handle it. This makes it handy for quick status checking.
The HEAD method is identical to GET except that the server MUST NOT
return a message-body in the response. The metainformation
contained in the HTTP headers in response to a HEAD request SHOULD be
identical to the information sent in response to a GET request. This
method can be used for obtaining metainformation about the entity
implied by the request without transferring the entity-body itself.
This method is often used for testing hypertext links for validity,
accessibility, and recent modification.
www.w3.org
$.ajax({
type: "HEAD",
async: true,
url: link,
dataType: 'json',
}).done(function(message,text,response){
const size = response.getResponseHeader('Content-Length');
//optionally you may check for the status code to know if the request has been successfully completed
const status = response.status;
});
Content-Length is one of the meta-data available in the head request which gives the size of the body in bytes, so by checking the size only without loading the whole page you could check if some content is available in the response body.
-
EDIT:
The above code is for dataType of json. For dataType of jsonp, callback functions for success and error properties will take of the response like the following:
$.ajax({
url: link,
dataType: 'jsonp',
crossDomain: true,
data: data,
success: function( data, status, jqxhr ){
console.log( "Response data received: ", data );
console.log("Response data length: ", data.length);
console.log("Response status code: ", status);
},
error:function(jqXHR, textStatus, errorThrown){
console.log("Error: ", errorThrown);
}
}
What you are trying to accomplish is not very specific, I'm not going to give you a code example on how to do this but here are some pointers.
There are different ways you could get a response: the status code is not tied to the response you get, you could have a 200 response and have no data, or have a 500 error with some data, this could be an html page showing the error or a json object, or even a string specifying what went wrong.
when you say "actually loads a page", I guess you are referring to an html response, you can check for the Content-Type header on your response headers and look for text/html and also check for Content-Length header to check if there is content in your response, and even if you check for those things it's hard to tell if the html actually displays any content.
It really depends on what are you looking specifically, my suggestion is check the Content-Type header and Content-Length and it also depends on the implementation of the website as every one might have different ways of implementing the HTTP protocol.
I'm posting successfully to my server , however when requests fails the error object is empty and i cannot construct logic based on the error code
Here is the code and what i see on DEV tools
$http({
method: 'POST',
url: 'my remote api/',
data: {'Account' : $scope.userPhoneNumber, 'Initiator' : initiator.toString()},
headers: {"Authorization": "Basic register:register"}
}).
then(function (response) {
console.log(response.data.AuthenticationUid);
openModalWindow(initiator, response.data.AuthenticationUid);
}, function (data) {
console.log(data);
$scope.phoneNotFound = true;
});
As you can see the printed data object shows status as -1 while it should show 404....
The console output indicates that you are not successfully POSTing to the server. Your OPTIONS request is successful, but your post fails due to missing 'Access-Control-Allow-Origin' headers which is indicative of a CORs error.
Without knowledge of your server it's a bit hard to give you an exact solution, but searching for something along the lines of 'setting up CORS in ' should get you on the right track.
I am using this code to get the data as text from a SOAP web service like this:
$(document).ready(function () {
$("#btn").click( function () {
alert("s");
$.ajax({
url: 'http://magicmap.skmm.gov.my/McmcServicemain_bb.asmx/Login?UserName=navdeep#gmail.com&Password=abc',
dataType: "text",
async: true,
success: function (result) {
alert(result);
},
error: function (request,error) {
alert('Network error has occurred please try again!'+request +error);
}
});
});
});
Here if I change the URL and use the same JSON using JSON GENERATOR then it works well and return the data perfectly.
Is there any difference in these two URL please help me I am stuck here from 2 days . I am new to JQuery . Thanks
The json-generator.com URL works because it supports Cross Origin Resource Sharing. It sets the response header:
Access-Control-Allow-Origin:*
This means that you can make cross domain requests. Your other URL doesn't output the CORS header and so the browser rejects the response.
To get your other URL to work, you'll have to proxy the request through a server side script on the same domain because of the Same Origin Policy.
I am trying to call a service which returns the data in json format. I am using jquery-ajax request to get that response data.
$('#butCallAjax').click(function () {
$.ajax({
url: 'my service url',
type: 'GET',
data: {},
success: function (data) {
if (data == "success") {
alert('request sent!');
}
},
error: function () {
alert('error');
}
});
});
using this code I am getting error
Origin 'servername' is not allowed by Access-Control-Allow-Origin.
Then I found some answers here and solved that by using dataType:'jsonp' in the request But when I use this dataType:'jsonp' then I am getting this error
Uncaught Syntax Error: Unexpected token :
I understand that this is because of Service is returning 'json' instead of jsonp.
So I am not able to figured it out that how to call a service that returns the json content and taking care of cross domain request.
Js Fiddle Try
That doesnt answer your question directly but its also a way to achieve what you're trying:
You can use:
/* java side: */
$.getJSON("URL?some_call_back_function=?", dataToPass, function(data){
// do whatever you like..
});
/* php side: */
if(isset($_GET['some_call_back_function']) && $_GET['some_call_back_function'] != ''){
$someJsonToReturn = array('Something'=> "something");
echo $_GET['some_call_back_function'].'('.json_encode($someJsonToReturn ).')';
}
i hope that helps. i use that usually when i want cross domain.
here is the jquery API for it:
getJson API
You are trying to make a cross domain call which fails.
I have modified your jsFiddle and added
async: false,
cache:false
Plus added errorObject parameter to the "Error" in ajax.
you can see my changes here
The answer I got now was "network error dom exception 19".
DOM Exception 19 refers to a "Network Error".
Is the URL that you are contacting in your Ajax call available?
Cross domain requests are possible if the server supports it! Before making the actual GET/POST call, the browser issues an OPTIONS call to the server to check whether it supports cross domain requests. Check if the server that you are contacting supports cross domain requests.
For more details on cross domain requests refer to this article which is very helpful:
using CORS