I tried a ReactJS fetch call to a REST-API and want to handle the response. The call works, i get a response, which i can see in Chrome Dev Tools:
function getAllCourses() {
fetch('http://localhost:8080/course', {
method: 'POST',
mode: 'no-cors',
credentials: 'same-origin',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
objectClass: 'course',
crud: '2'
})
}).then(function (response) {
console.log(response);
return response.json();
}).catch(function (err) {
console.log(err)
});
}
When i try to handle the response, i got a "SyntaxError: Unexpected end of input" at
return response.json();
The console.log looks like this:
My Response JSON looks like this, it is valid, i checked it with jsonlint:
[
{
"0x1": {
"users": [],
"lectures": [],
"owner": "0x2",
"title": "WWI 14 SEA",
"description": null,
"objectClass": "course",
"id": "course_00001"
},
"0x2": {
"username": "system",
"lectures": [],
"course": null,
"solutions": [],
"exercises": [],
"roles": [
"0x3",
"0x4",
"0x5"
],
"objectClass": "user",
"id": "user_00001"
},
"0x3": {
"roleName": "ROLE_ADMIN",
"objectClass": "role",
"id": "role_00001"
},
"0x4": {
"roleName": "ROLE_STUDENT",
"objectClass": "role",
"id": "role_00002"
},
"0x5": {
"roleName": "ROLE_DOCENT",
"objectClass": "role",
"id": "role_00003"
}
}
]
You need to remove the mode: 'no-cors' setting from your request. Setting no-cors mode is exactly the cause of the problem you’re having.
A no-cors request makes the response type opaque. The log snippet in the question shows that. Opaque means your frontend JavaScript code can’t see the response body or headers.
https://developer.mozilla.org/en-US/docs/Web/API/Request/mode explains:
no-cors — JavaScript may not access any properties of the resulting Response
So the effect of setting no-cors mode is essentially to tell browsers, “Don’t let frontend JavaScript code access the response body or headers under any circumstances.”
People sometimes try setting no-cors mode when a response doesn’t include the Access-Control-Allow-Origin response header or else because the request is one that triggers a CORS preflight, and so your browser does an OPTIONS preflight.
But using no-cors mode isn’t a solution to those problems. The solution is either to:
configure the server to which you’re making the request such that it sends the Access-Control-Allow-Origin response header, and such that it handles OPTIONS requests
or set up a CORS proxy using code from https://github.com/Rob--W/cors-anywhere/ or such; see the How to use a CORS proxy to get around “No Access-Control-Allow-Origin header” problems section of the answer at No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API
In your then you should check if the response is OK before returning response.json:
.then(function (response) {
if (!response.ok) {
return Promise.reject('some reason');
}
return response.json();
})
If you want to have the error message in your rejected promise, you can do something like:
.then(function (response) {
if (!response.ok) {
return response.text().then(result => Promise.reject(new Error(result)));
}
return response.json();
})
I know this answer might be super late and might have been resolved but i just had the same issue today and I just needed to add a ',' at the end of the headers hash and i stopped getting the error
export function addContacts(formData) {
return(dispatch) => {
dispatch({type: 'POSTING_CONTACTS'});
console.log(formData)
return fetch(uri, {
method: 'POST',
body: JSON.stringify({contact: {name: formData.name, phone_number: formData.phoneNumber}}),
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
})
.then(response => {
return response.json()
}).then(responseJSON => {
console.log(responseJSON)
return dispatch({type: 'ADD_CONTACT', payload: responseJSON});
})
}
}
You can avoid the problem with CORS policy by adding in the header of php or another server endpoint the row:
<?php
header('Access-Control-Allow-Origin: *');
//or
header('Access-Control-Allow-Origin: http://example.com');
// Reading JSON POST using PHP
$json = file_get_contents('php://input');
$jsonObj = json_decode($json);
// Use $jsonObj
print_r($jsonObj->message);
...
// End php
?>
Model of working fetch code with POST request is:
const data = {
optPost: 'myAPI',
message: 'We make a research of fetch'
};
const endpoint = 'http://example.com/php/phpGetPost.php';
fetch(endpoint, {
method: 'POST',
body: JSON.stringify(data)
})
.then((resp) => resp.json())
.then(function(response) {
console.info('fetch()', response);
return response;
});
Simply copy the following code and paste it on your web.config file under <system.webServer> tag.
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
Related
I am building a JS Script to capture some data from the URL, this script is installed on a third-party app, so the flow is:
the user opens an URL, the Third part runs my script, my script captures that info and sends that to my server (RAILS 6), and then the third part redirects the user.
my implementation works well in chrome, but not in firefox:
console.log('before send')
try {
const response = await axios({
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
method: 'post',
url: constants.SERVER_ADDRESS,
data: click,
})
if (response.ok) {
console.log(response.json())
} else {
console.log('bad server response');
}
} catch (err) {
console.log(err)
console.log(`server error: ${err.message}`);
}
console.log('after send')
so the error that I got in firefox is: 'Error: Request aborted' and the error object doesn't have much more info.
I presume that could be an error related to my server CORS configuration?
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'localhost:3000', 'myserver.com'
resource '/api/v1/*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
allow do
origins '*'
resource '/api/v1/public/*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
what kind of configuration am I missing? or what am I doing wrong?
EDIT 1:
Looking into the details of the error with: console.log(err.toJSON())
I saw:
{
"message": "Request aborted",
"name": "Error",
"fileName": "https://server.amazonaws.com/dev.click.js",
"lineNumber": 667,
"columnNumber": 15,
"stack": "createError#https://...\n",
"config": {
"url": "http://localhost:3000/api/v1/public/click/",
"method": "post",
"data": "{...}",
"headers": {
"Accept": "application/json",
"Content-Type": "application/json"
},
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1
},
"code": "ECONNABORTED"
}
And seeing into the AXIOS Code:
...
// Handle browser request cancellation (as opposed to a manual cancellation)
request.onabort = function handleAbort() {
if (!request) {
return;
}
reject(createError('Request aborted', config, 'ECONNABORTED', request));
// Clean up request
request = null;
};
that makes me think is more probably a miss configuration in Axios that makes firefox cancel the request, that make sense?
EDIT 2:
I ran the same routine using fetch instead of Axios, and I had the same result: the request worked well on chrome, but not in Firefox (or other browsers)
At this time I can perform succesfully my Postman request to get my token. I'm using these parameters :
-Basic Authorization in the headers
-and this body
-
Now I would like to get this request as a pre-request script (and use an environment variable for the token).
Here is the script :
pm.sendRequest({
url: 'http://localhost:8084/oauth/token',
method: 'POST',
header: {
'Authorization':'Basic Y2xpZW50OnBhc3N3b3Jk',
'content-type': 'application/x-www-form-urlencoded'
},
data:{
'password':'secret',
'username':'admin',
'grant_type':'password'
}
}, (err, res) => pm.environment.set("token", res.json().access_token));
It doesn't work with the response : Full authentication is required to access this resource.
What is wrong?
Thanks
You could change the data section to something like this?
body:{
mode:"urlencoded",
urlencoded:[
{
key:"grant_type",
value:"password"
},
{
key:"username",
value:"admin"
},
{
key:"password",
value:"secret"
}
]
}
A great resource for pm.sendRequest() examples can be found here
I am working with the Hubspot API and I am trying to modify the close date of a deal via the "PUT" Method by sending JSON Data. But I am getting errors such as
{ status: 'error', message: 'Invalid input JSON on line 1, column
15: Can not deserialize instance of java.util.ArrayList out of
START_OBJECT token', correlationId:
'b8b47229-184d-40b3-b402-9e3dd684b217', requestId:
'd364fe8dac5e876639928dd0d04045fd' }
This is the code that I have written-
fetch('https://api.hubapi.com/deals/v1/deal/103361780?hapikey=', {
method: 'put',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify({"properties":{name: "closedate", "value": 1528744207881}})
}).then(res=>res.json())
.then(res => console.log(res));
This is the JSON Data that I am trying to pass
{
"properties":[
{
"name": "closedate",
"value": 1528744207881
}
]
};
And here is the documentation of making a PUT request via the Hubspot API.
I am able to successfully update the value via POSTMAN.
Any help on this matter would be greatly appreciated.
You are missing brackets - [] and on the backend, they are waiting for an array to deserialize it to Arraylist.
Try fetch with this body:
{"properties":[{"name": "closedate", "value": 1528744207881}]}
So I have a funny little problem.
When calling my API from an AngularJS client with the following code, everything works fine, except that my API only recieves an empty object as data:
var req = {
method: 'Post',
url: config.API + request.toLowerCase() + '/',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: data
}
$http(req)
.then(function(response){
// handling response
})
Now, if I remove the headers: { 'Content-Type': 'application/x-www-form-urlencoded' } or changes it to headers: { 'Content-Type': 'application/json' } I get the this error:
The requested resource does not support http method 'OPTIONS'
My API controller looks like this:
[EnableCors("*", "*", "*")]
[HttpPost]
public string Post([FromBody]dynamic value)
{
// Do some stuff
Response response = new Response();
return JsonConvert.SerializeObject(response);
}
What I'm looking for is a way to prevent the tiresome "OPTIONS not supported" error, and still be able to send dynamic data to my controller
EDIT
Regarding the duplicate, I've already tried their approach, hence why I already are using [EnableCors] in my controller. But if I add this:
public static void Register(HttpConfiguration config)
{
config.EnableCors();
}
I get this error instead
Response to preflight request doesn't pass access control check: The
'Access-Control-Allow-Origin' header contains multiple values '*, *',
but only one is allowed. Origin 'http://localhost:82' is therefore not
allowed access
I'm trying to POST to an API endpoint on my server. I know my endpoint works because if I use Advanced REST Client, I can hit it and get a JSON response as expected. The problem seems to be that no data is being sent in the body of my request despite calling request.write(postData) which contains a key, value pair. Without this data being sent in the body, my server returns a 401 error as expected without this information. Printing out the content of the POST server-side is empty but I'm clueless as to why it's empty.
var postData = querystring.stringify({
"access_token" : accessToken,
"id": applianceId
});
var serverError = function (e) {
log("Error", e.message);
context.fail(generateControlError(requestName, "DEPENDENT_SERVICE_UNAVAILABLE", "Unable to connect to server"));
};
var callback = function(response) {
var str = "";
response.on("data", function(chunk) {
str += chunk.toString("utf-8");
});
response.on("end", function() {
result = generateResult(CONTROL, requestName.replace("Request", "Confirmation"), messageId);
context.succeed(result);
});
response.on("error", serverError);
};
var options = {
hostname: REMOTE_CLOUD_HOSTNAME,
port: 443,
path: REMOTE_CLOUD_BASE_PATH + "/" + endpoint,
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
};
var request = https.request(options, callback);
request.on("error", serverError);
//This doesn't seem to write anything since if I print out the POST
//data server-side it's empty; however, if I print out the value of
//postData here, it looks as expected: 'access_token=xxxxx'
request.write(postData);
request.end();
I have testing you code again httpbin.org/post and it seems that it is working.
I believe that the issue related to, that your should POST application/json and not "application/x-www-form-urlencoded
Please try to change the header
headers: {
"Content-Type": "application/json"
}
Then, try to change the postData to JSON string:
var postData=JSON.stringify({access_token:"xxxxx"})
To be sure that problem you success to send and the problem is not local (maybe there is an issue in your server), change the target to mirror URL:
var options = {
hostname: "httpbin.org",
path:'/post',
port: 443,
method: "POST",
headers: {
"Content-Type": "application/json"
}
};
If there is no problem in your NodeJS version, the is the response you should get: (It is mean that the server got the posted data)
{
"args": {},
"data": "{\"access_token\":\"xxxxx\"}",
"files": {},
"form": {},
"headers": {
"Content-Length": "24",
"Content-Type": "application/json",
"Host": "httpbin.org"
},
"json": {
"access_token": "xxxxx"
},
"origin": "5.29.63.30",
"url": "https://httpbin.org/post"
}
BTW: I really recommend you to move to a library to manage the request for you:
https://github.com/request/request - Very popular
https://github.com/request/request-promise - For popular who like to use the Promise syntax (The next thing in JavaScript)
https://github.com/visionmedia/superagent - For people who like to write same code in Browser & Server