Background:
The following AJAX code works successfully (ReactJS + JQuery frontend, PHP backend).
const data = {request_type:"load_data", start:1, end:50};
$.ajax({
type: "POST",
url: "http://localhost/site/server.php",
data: data,
dataType: "json",
success: (JSobject) => {
this.setState({arr: JSobject.arr});
}
});
In Chrome Dev Tools server.php's Headers show up as "Form Data" like so:
At the PHP server backend, there's this line of code:
$request_type = $_POST["request_type"];
In an attempt to learn how to do Fetch (I've avoided it so far mostly because I had AJAX boilerplate that worked well), I've been playing around with trying to build a drop-in replacement for the above code.
I tried this:
const data = {request_type:"load_data", start:1, end:50};
fetch("http://localhost/site/server.php", {
method: "POST",
body: data
})
.then((JSobject) => {
this.setState({arr: JSobject.arr});
});
But I get this PHP error:
Notice: Undefined index: request_type in .....server.php
And in Chrome Dev Tools server.php's Headers show up like so:
So, I tried changing the data to JSON.stringify(data) like so:
const data = {request_type:"load_data", start:1, end:50};
fetch("http://localhost/site/server.php", {
method: "POST",
body: JSON.stringify(data)
})
.then((JSobject) => {
this.setState({arr: JSobject.arr});
});
But I still get the exact same PHP error:
Notice: Undefined index: request_type in .....server.php
And in Chrome Dev Tools server.php's Headers show up like so:
Out of general frustration (although it's pointless because I'd be still using JQuery), I thought I'd use JQuery's $.param(), and that would surely work.
So I tried this:
const data = $.param({request_type:"load_data", start:1, end:50});
fetch("http://localhost/site/server.php", {
method: "POST",
body: data
})
.then((JSobject) => {
this.setState({arr: JSobject.arr});
});
Still get the same PHP error
Notice: Undefined index: request_type in .....server.php
And in Chrome Dev Tools server.php's Headers show up like so:
My question: how do I modify the Fetch code above so that it becomes a drop-in replacement for the AJAX code up top.
I realize that the use of horizontal lines can be bothersome for some. You can give yourself permission to believe that it really helps a lot of us regular folks follow what's going on in the question.
Answering my own question for others who might encounter this issue in future (and also for my own reference). Figured out the answer via this link and this link. The following code worked:
fetch("http://localhost/site/server.php", {
method: "POST",
body: JSON.stringify(data)
}).then(response => {
return response.json();
}).then((JSobject) => {
this.setState({arr: JSobject.arr});
});
I had to change some PHP code on the server. The initial "gatekeeper" code was:
$_POST = array_map("trim", $_POST);
$request_type = $_POST["request_type"];
This had to be commented out:
$_POST = array_map("trim", $_POST); //this had to be commented out
And this had to be added instead:
$content = trim(file_get_contents("php://input"));
$_POST = json_decode($content, true);
And in Chrome Dev Tools server.php's Headers show up as "Request Payload":
I also saw some suggestions to add a "headers" key like so:
fetch("http://localhost/site/server.php", {
method: "POST",
headers: {"Content-Type": "application/x-www-form-urlencoded",},
body: JSON.stringify(data)
}).then(response => {
return response.json();
}).then((JSobject) => {
this.setState({arr: JSobject.arr});
});
This did also work, but in Chrome Dev Tools server.php's Headers show up as "Form Data":
Another way to do this is by wrapping the object (to be sent) in JQuery's $.param() (I was interested in this because I often use $.param() to append key-values to form.serialize(), on the client side before sending to the PHP on the server)
const data = $.param({request_type:"load_data", start:1, end:50});
fetch("http://localhost/site/server.php", {
method: "POST",
headers: {"Content-Type": "application/x-www-form-urlencoded",},
body: data
}).then(response => {
return response.json();
}).then((JSobject) => {
this.setState({arr: JSobject.arr});
});
The advantage of doing it this way was that no changes were needed to the code on the server side.
In Chrome Dev Tools server.php's Headers show up as"Form Data":
Without using JQuery:
Re: the previous method (using $.param()), it's possible to do it completely without JQuery, but then one would need some function to chain the javascript object's key-value pairs while properly encoding special characters as x-www-form-urlencoded (this link explains how to do it).
E.g., instead of this:
const data = $.param({request_type:"load_data", start:1, end:50});
...
body: data
One would do this:
const data = {request_type:"load_data", start:1, end:50};
...
...
body: "request_type=load_data&start=1&end=50"
Related
Im new to ajax. I was trying to find the answer but was not lucky to find the corresponsing one. Basically I need to use an ajax to get some data and after that to put this data to the variable that later will be used as an attribute for the callback function with custom code.
This ajax part is just a method of myObject.
So, in the end I need this kind of functionality:
myObject.getData(url, callback(data) {
//my custom code of what I wanna do after ajax is complete
});
My code
/*
HERE COME SOME PROPERTIES AND OTHER METHODS WICH IS NOT THE CASE
*/
//This is where Im stuck
var getData = function getFromUrl($url) {
$.ajax({
type: 'get',
url: $url,
dataType: 'html',
success: function(html) {
$obj = html;//Im lost on this step!
},
});
};
P.S. Im trying to find an async way (without using async:false). Hope its possible
First I encountered many problems. My first problem was No Access-Control-Allow-Origin, most websites dont allow you to just scrap get their data for security reasons. Luckily someone already made a proxy: http://cors.io/ . Second problem is that you cant embed http on https, so I cant use jsfiddle to show you this working, it works on my local enviroment. After you get the raw html you have to parse it, you can do it with full regex, or you can power yourself with jquery like I'm doing on this example. What we're doing is checking stackoverflow.com and getting the amount of featured questions with .find(".bounty-indicator-tab").first().html(); But once you have the full html you can get any data you need.
var getData = function getFromUrl(url) {
$.ajax({
url: 'http://cors.io/?' + url,
crossDomain: true,
dataType: 'html',
success: function (html) {
var match = $(html).find(".bounty-indicator-tab").first().html();
console.log(match);
return match;
},
error: function(e) {
console.log('Error: '+e);
}
});
};
url = 'http://stackoverflow.com/';
data = getData(url);
//You cant use data yet because its working async
I'm using ReactJS and changing a simple local database setup to a Parse.com class adapting a link saver from this repo: https://github.com/peterjmag/reading-list
I want to switch the fetch call for the native to parse .save()
Can I use the fetch or should I rewrite the function to use the parse.com language?
Adding the link is declared on this
LinkActions.addLink.listen(function (link) {
fetch('//localhost:3001/links/', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: link.url
})
})
.then(function(response) {
if (response.status >= 400) {
throw new Error('Bad response from server');
LinkActions.addLink.failed(link);
}
return response.json();
}).then(function (newLinkData) {
LinkActions.addLink.completed(link, newLinkData);
});
});
EDIT
The new code looks something like this:
OK. So my new code looks something like this now.
LinkActions.addLink.listen(function(link) {
var LinkListing = Parse.Object.extend("LinkListing");
var linkListing = new LinkListing();
linkListing.save({
url: link.url
}, {
success: function(linkListing) {
// The object was saved successfully.
},
error: function(linkListing, error) {
// The save failed.
// error is a Parse.Error with an error code and message.
}
});
});
Am I missing something?
You can either keep the fetch and use the parse.com REST API, or refactor your code to use the Javascript API, icnluding functions such as save. I recommend refactoring to the Javascript API because it would make your code much shorter and clearer.
For example, two things which definitely shouldn't be your concern are adding headers to every request and comparing every response status to 400.
I'm trying to extract some projects from the Asana api with vue-resource (https://github.com/vuejs/vue-resource), a Vue.js add-on that makes ajax calls simple. I'm using an api key to access Asana, but I can't figure out how to pass the key in the request header using vue-resource.
In jQuery this works, using beforeSend:
$.ajax ({
type: "GET",
url: "https://app.asana.com/api/1.0/projects?opt_fields=name,notes",
dataType: 'json',
beforeSend: function(xhr) {
xhr.setRequestHeader("Authorization", "Basic " + "XXXXXX");
},
success: function (data){
// console.log(data);
}
});
Where XXXXXX is the Asana api key + ':' converted with btoa(). https://asana.com/developers/documentation/getting-started/authentication
Without needing to authenticate, the Vue instance should be fine with a simple request in the ready function:
new Vue({
el: '#asana_projects',
data: {
projects : []
},
ready: function() {
this.$http.get('https://app.asana.com/api/1.0/projects?opt_fields=name,notes', function (projects) {
this.$set('projects', projects); // $set sets a property even if it's not declared
});
},
methods: {
// functions here
}
});
This, of course, returns a 401 (Unauthorized), since there is no api key in there.
On the vue-resource github page there is also a beforeSend option for the request, but even though it is described right there I can't seem to figure out the correct syntax for it.
I have tried
this.$http.get( ... ).beforeSend( ... );
// -> "beforeSend is not a function", and
this.$http.get(URL, {beforeSend: function (req, opt) { ... }, function(projects) { //set... });
// -> runs the function but req and opt are undefined (of course)
I realize I'm being less than clever as I fail to understand a syntax that is right there in the documentation, but any and all help would be much appreciated!
Any takers?
Perhaps I'm missing some subtlety but can't you use the options parameter to the $get call to specify the header? From the docs: https://github.com/vuejs/vue-resource#methods
Methods
Vue.http.get(url, [data], [success], [options])
[...]
Options
[...]
headers - Object - Headers object to be sent as HTTP request headers
[...]
So for instance:
this.$http.get(
'https://app.asana.com/api/1.0/projects?opt_fields=name,notes',
function (projects) {
this.$set('projects', projects); // $set sets a property even if it's not declared
},
{
headers: {
"Authorization": "Basic " + "XXXXXX"
}
}
);
You can also configure the auth token for all calls like this:
Vue.http.options.root = '/root';
Vue.http.headers.common['Authorization'] = 'Basic YXBpOnBhc3N3b3Jk';
See the docs
I have spend over 10 hours trying to figure this out and looking at similar examples from other people but unfortunately I haven't been able to find out what's my problem here.
I have a ServiceStack Webservice setup:
http://example.com/v1/getuser?code=abcd&lastname=doe&format=json
If I run the above via the browser I will get the following:
[{"nameresult":"joe"}]
I am trying to get this via making an ajax call as follow:
var code = $("#code_field").val();
var lastname = $("#lastname_field").val();
$.ajax({
url: "http://example.com/v1/getuser",
type: "POST",
data: JSON.stringify({
code: code,
lastname: lastname,
format: 'json'
}),
contentType: "application/json; charset=utf-8",
success: function (data) {
var returned_data = data;
alert('returned_data=' + returned_data);
},
error: function (xhRequest, ErrorText, thrownError) {
console.log('xhRequest: ' + xhRequest + "\n");
console.log('ErrorText: ' + ErrorText + "\n");
console.log('thrownError: ' + thrownError + "\n");
}
});
When I run the above, I get the following:
returned_data=[object Object]
Does anyone knows how could I get the json result, nameresult=joe? I am assuming that [object Object] contains [{"nameresult":"joe"}] but I am not entirely sure because I cannot see inside the object :(. thanks so much.
LATEST UPDATE - PROBLEM SOLVED!
I figured out the problem I was having. It had to do with ServiceStack and not with the Ajax call. My problems was the following, I hope it helps someone else one day that may face the same issue.
1.- I needed to enable CORS support on ServiceStack in order to allow posting parameters from Ajax:
File: AppHost.cs
//Permit modern browsers (e.g. Firefox) to allow sending of any REST HTTP Method
base.SetConfig(new EndpointHostConfig
{
GlobalResponseHeaders = {
{ "Access-Control-Allow-Origin", "*" },
{ "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" },
{ "Access-Control-Allow-Headers", "Content-Type" },
},
});
Plugins.Add(new CorsFeature());
this.RequestFilters.Add((httpReq, httpRes, requestDto) =>
{
//Handles Request and closes Responses after emitting global HTTP Headers
if (httpReq.HttpMethod == "OPTIONS")
httpRes.EndServiceStackRequest(); //httpExtensions method
// =>after v.3.9.60, => httpRes.EndRequestWithNoContent();
});
2.- My getuser method was in the GET instead of POST. I moved that to the POST and problem solved.
Moved getuser from here: public object Get(...) into here public object Post(...)
Thanks to all for helping me figure this out.
Use console.log to output returned_data by itself:
console.log(returned_data);
This will display the JSON object:
{"nameresult":"joe"}
Your original alert concatenates the string "returned_data=" with the JSON object, and thus the object is converted to a placeholder string "[object Object]" by the browser.
I often put my label in one log, and the object in another:
console.log('returned_data:');
console.log(returned_data);
A few colleagues and I have a problem whereby the response from an ajax call returns some unexpected content. Rather than getting a simple JSON object back with various properties, the value of result.responseText is the HTML markup of a generic 406 status error page, saying the MIME type is not accepted by the browser.
The call is made like so:
$.ajax({
url: '/promociones/cincogratis/canjear-codigo-promocional',
type: this.method,
data: $(this).serialize(),
success: function (result) {
$('.promotion_banner .loader').hide();
$('.promotion_banner').html(result);
},
error: function (result) {
var obj = result.responseText;
if (obj.isRedirect) {
document.location = obj.redirectUrl;
}
else {
$('.promotion_banner .loader').hide();
$(".error-wrapper").removeClass("hidden");
var generic_error = document.getElementById('generic_error').value;
$(".error-wrapper p").html(generic_error);
}
},
beforeSend: function() {
$('.promotion_banner .loader').show();
}
});
The controller response to the call is like so:
Response.StatusCode = (int)HttpStatusCode.NotAcceptable; // 406
return Json(new { errorMessage = LocalErrorMessages.Website_Promotions_FreeFiver_General_Problem, isRedirect = false } );
We would expect result.responseText to contain key values for errorMessage and isRedirect, but they’re not there.
It’s worth pointing out that this code is multi-tenanted, shared by the current application and another one, where it works absolutely fine.
We’ve tried:
- Configuring IIS to show detailed error responses rather than a custom page for more detail – gives us nothing extra towards solving the problem.
- Allowing all response content types to the call
- Changing the culture of our site (which is currently es-ES)
- Various web.config tweaks
Has anyone ever had this problem?
Simplify your request. Maybe something like:
$.ajax({
url: '/promociones/cincogratis/canjear-codigo-promocional',
type: 'GET',
data: {foo:'bar', one:'two'},
dataType: 'json',
success: function (result) {
console.dir(result);
},
error: function (xhr) {
console.dir(xhr)
}
});
And post the response from the server. This kind of error seems a request problem rather than server configuration issue