in a $http error handler, I need to differentiate a real HTTP error from cancelled requests.
Here is an example:
app.controller('Ctrl', function ($http, $q) {
const vm = this;
this.errors = [];
vm.errorHandler = (label) => ((error) => {
this.errors.push(label + ' : \n\n' + JSON.stringify(error, null, 2));
});
vm.unResolved = () => {
$http({
method: 'GET',
url : 'https://Idonotexist'
}).catch(vm.errorHandler('unResolved'));
}
vm.cancelled = () => {
const canceller = $q.defer()
$http({
method: 'GET',
timeout: canceller.promise,
url : 'https://www.googleapis.com/books/v1/volumes?q=isbn:0747532699'
}).catch(vm.errorHandler('cancelled'));
canceller.resolve();
}
vm.unsecured = () => {
$http({
method: 'GET',
url : 'http://Idonotexist'
}).catch(vm.errorHandler('unsecured'))
}
});
In my errorHandler function, I want to differentiate cancelled requests from a real error (such as "insecured" or "unresolved hosts").
It would be a real pain for me to pass the canceller to the error handler and it won't be able to treat correctly requests cancelled by the browser without an angularjs canceller.
So far, here are the errors I get in my error handler.
Error for non cancelled (host unresolved) request :
{
"data": null,
"status": -1,
"config": {
"method": "GET",
"transformRequest": [
null
],
"transformResponse": [
null
],
"jsonpCallbackParam": "callback",
"url": "https://Idonotexist",
"headers": {
"Accept": "application/json, text/plain, */*"
}
},
"statusText": ""
}
Error for cancelled request :
{
"data": null,
"status": -1,
"config": {
"method": "GET",
"transformRequest": [
null
],
"transformResponse": [
null
],
"jsonpCallbackParam": "callback",
"timeout": {
"$$state": {
"status": 1,
"processScheduled": false,
"pur": true
}
},
"url": "https://www.googleapis.com/books/v1/volumes?q=isbn:0747532699",
"headers": {
"Accept": "application/json, text/plain, */*"
}
},
"statusText": ""
}
I have a config.timeout that contains the promise but I would like to avoid using it. I would like to treat as cancelled requests requests cancelled by the browser even if no canceller.
Here is a jsfiddle with the example.
Is there a way to add a interceptor on cancelled requests to flag then specifically ?
UPDATE
This can't be solved angularjs $http code does not separate error than timeout or abort. You can see it here.
A pull request is running about it.
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)
I have a simple function to test on my application:
this.$userService.getRestaurantsList(userTemp).then(
response => {
console.log(response);
console.log('FUNCIONOU');
}
);
Because I getting errors when I make this simple post, and is giving me this:
Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
This is not CORS my server is configured fine with CORS.
When we go deep to getRestaurantsList method I have this:
getRestaurantsList(user) {
return axios.post(configMain.MAIN_URL + this.GET_COMPANY_RESTAURANT_LIST_URL, JSON.stringify(user));
}
I want to send data like RAW data with AXIOS but if I use stringify it works the post, but if I use like this
getRestaurantsList(user) {
return axios.post(configMain.MAIN_URL + this.GET_COMPANY_RESTAURANT_LIST_URL, user);
}
Only the JSON data it gives me the error you guy see above, and in my API is just returning the data for testing :
This is from LARAVEL API
public function getAllRestaurants2(Request $request)
{
return $this->sendResponse($request->all(), 'Restaurants retrieved successfully');
}
Some update what I'm working on, if I send like this is working:
return axios.post(configMain.MAIN_URL + this.GET_COMPANY_RESTAURANT_LIST_URL, null, {
params: {
search: user
}
});
Only this approach that is not working:
return axios.post(configMain.MAIN_URL + this.GET_COMPANY_RESTAURANT_LIST_URL, user);
Here is my interceptor using STRINGFY and working fine log:
{
"url": "url",
"method": "post",
"data": "{\"loja\":\"teste\"}",
"headers": {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/x-www-form-urlencoded"
},
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1
}
Now the interceptor using the wrong approach:
{
"url": "url",
"method": "post",
"data": "{\"id\":\"\",\"name\":\"Anderson Teste\",\"email\":\"teste#email\",\"client_restaurant_id\":11,\"company_id\":1,\"cpf\":\"\",\"phone\":\"81293932921393\",\"locations\":[],\"password\":\"123mudar\"}",
"headers": {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/json;charset=utf-8"
},
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1
}
Here is my configuration from CORS package :
[
'paths' => ['project/api/*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
];
What I'm doing wrong that posting like JSON data format is giving me errors?
you will need to make the getRestaurantsList function asynchronous.
try this code.
getRestaurantsList(user) async {
return await axios.post(configMain.MAIN_URL + this.GET_COMPANY_RESTAURANT_LIST_URL, user);
}
I am trying to create a fetch call to servicedesk plus system but I keep getting 400 error, I understand that the request I made is not what the server wanted but in postman, I do manage to send that same query successfully. I can't understand what is the problem
In the dev tools network tab I see this data after dending the Json:
response_status: {status_code: 4000,…}
messages: [{status_code: 4001, field: "input_data", type: "failed", message: "JSON cant be analyzed"}]
0: {status_code: 4001, field: "input_data", type: "failed", message: "JSON cant be analyzed"}
field: "input_data"
message: "JSON cant be analyzed"
status_code: 4001
type: "failed"
status: "failed"
status_code: 4000
From what I read in the API documentation I saw that the 4001 error means that the ID or the name are not as they are in the service desk system.
here is a link to the API docs
this is my code:
const jss = {
"request": {
"subject": "test 29072020",
"description": "TEST REQUEST BY DAVID",
"requester": {
"id": "1231",
"name": "david"
},
"resolution": {
"content": "Mail Fetching Server problem has been fixed"
},
"status": {
"name": "פתוחה"
},
"template": {
"name": "Test for API",
"id": "123123"
},
}
}
const sendToSd = document.getElementById('send');
sendToSd.addEventListener('click', submitData);
var mydata = JSON.parse(jss);
var stringify = JSON.stringify(mydata);
async function submitData(){
const url = 'http://MYURL.COM/api/v3/requests?TECHNICIAN_KEY=SOME-STRING&input_data='+stringify+'&FORMAT=json';
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
console.log('response',response)
}
This fetch works and manages to retrieve the data from the service desk using the same URL and TECHNICIAN_KEY.
// fetch('http://MYURL.COM/api/v3/requests/61627?TECHNICIAN_KEY=SOME-STRING', {
// method: 'GET'
// })
// .then(response => {
// console.log(response);
// return response;
// });
I am trying to get the current user from https://graph.microsoft.com/v1.0/me.
I get a valid token, however, the request to https://graph.microsoft.com/v1.0/me gives me a 404.
var token;
$(document).ready(function () {
requestToken();
});
function requestToken() {
$.ajax({
"async": true,
"crossDomain": true,
"url": "https://cors-anywhere.herokuapp.com/https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token",
"method": "POST",
"headers": {
"content-type": "application/x-www-form-urlencoded"
},
"data": {
"grant_type": "client_credentials",
"client_id ": "{client_id}",
"client_secret": "{client_secret}",
"scope ": "https://graph.microsoft.com/.default"
},
success: function (response) {
console.log(response);
token = response.access_token;
getUserInformation();
},
error: function (error) {
console.log(JSON.stringify(error));
}
})
}
function getUserInformation() {
$.ajax({
method: 'GET',
url: "https://graph.microsoft.com/v1.0/me",
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json'
},
}).success(function(response) {
console.log(response);
}).error(function(error) {});
}
Anyone knows what might be the problem?
Thank you.
I got a detailed response:
"error": {
"code": "Request_ResourceNotFound",
"message": "Resource '' does not exist or one of its queried reference-property objects are not present.",
"innerError": {
"request-id": "",
"date": "2020-04-17T09:33:43"
}
}
}
from https://graph.microsoft.com/v1.0/me
I got:
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token is empty.",
"innerError": {
"date": "2020-10-20T11:39:50",
"request-id": "becb1443-91e3-42d9-9c77-b9808aaf2cf7",
"client-request-id": "becb1443-91e3-42d9-9c77-b9808aaf2cf7"
}
}
}
https://graph.microsoft.com/.default
{
"error": {
"code": "BadRequest",
"message": "Invalid version.",
"innerError": {
"date": "2020-10-20T11:41:04",
"request-id": "3fdd24bd-7c96-4ff2-9e18-fc042673ecd2",
"client-request-id": "3fdd24bd-7c96-4ff2-9e18-fc042673ecd2"
}
}
}
Usually, request returns 404 status code when the route does not exist, So I'll recommend you to please check the provided URI is valid or not.
can you please help me how to get to work POST method in vanilla JS (without jQuery)?
I am trying to do it with this code:
var call =
{
"filterParameters": {
"id": 18855843,
"isInStockOnly": false,
"newsOnly": false,
"wearType": 0,
"orderBy": 0,
"page": 1,
"params": {
"tId": 0,
"v": []
},
"producers": [],
"sendPrices": true,
"type": "action",
"typeId": "",
"branchId": ""
}
};
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://www.alza.cz/Services/RestService.svc/v2/products');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
if (xhr.status === 200) {
console.log('OK ' + xhr.responseText);
}
else if (xhr.status !== 200) {
console.log('Request failed. Returned status of ' + xhr.status);
}
};
xhr.send(call);
And constantly getting error 400 (Bad request).
I have tried to call it in jQuery and it is working, but I need to get it work in plain JS.
Please, any idea why it is not working?
For check, here is the working code in jQuery:
addData({
"filterParameters": {
"id": 18855843,
"isInStockOnly": false,
"newsOnly": false,
"wearType": 0,
"orderBy": 0,
"page": 1,
"params": {
"tId": 0,
"v": []
},
"producers": [],
"sendPrices": true,
"type": "action",
"typeId": "",
"branchId": ""
}
}
);
function addData(data){// pass your data in method
$.ajax({
type: "POST",
url: "https://www.alza.cz/Services/RestService.svc/v2/products",
data: JSON.stringify(data),// now data come in this function
contentType: "application/json; charset=utf-8",
crossDomain: true,
dataType: "json",
success: function (data, status, jqXHR) {
console.log(data);// write success in " "
},
error: function (jqXHR, status) {
// error handler
console.log(jqXHR);
alert('fail' + status.code);
}
});
}
You must set the content-type header to application/json You are posting json data as formdata which is wrong (beside you have forgotten to stringify your object)
xhr.setRequestHeader('Content-Type', 'application/json');
Heres is a working example using the new vanilla js fetch API
var result = null
fetch("https://www.alza.cz/Services/RestService.svc/v2/products", {
method: "POST",
body: JSON.stringify({
"filterParameters": {
"id": 18855843,
"isInStockOnly": false,
"newsOnly": false,
"wearType": 0,
"orderBy": 0,
"page": 1,
"params": {
"tId": 0,
"v": []
},
"producers": [],
"sendPrices": true,
"type": "action",
"typeId": "",
"branchId": ""
}
}),
headers: {"content-type": "application/json"},
//credentials: 'include'
})
.then(function(res) {
if (res.ok) { // ok if status is 2xx
console.log('OK ' + res.statusText);
} else {
console.log('Request failed. Returned status of ' + res.status);
}
return res.blob()
})
.then(function(blob) {
result = blob
// window.result = blob
})
It's the Access-Control-Allow-Origin response blocking the Javascript code to AJAX access the server data. If the server is not controlled by you, you need another server to fetch the data instead, before it can redirect to your webpage.
So I just tried xhr.send()
and got
XMLHttpRequest cannot load https://www.alza.cz/Services/RestService.svc/v2/products. Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'http://www.alza.cz' that is not equal to the supplied origin.
However if I try this on a blank tab, it actually works.
what url are you trying to run this JS from?
Try running the JS from a blank tab.