I was wondering if there is any way to send the same header to different requests.
I saw this AngularJS $http custom header for all requests but http interceptor is for all http requests and I don't want that each http request get this header.
There is other way to do this for different request without sending it manually for each request?
Sorry for my english and thanks in advance!
Yes you can ! below is an example straight from the Docs:
var req = {
method: 'POST',
url: 'http://example.com',
headers: {
'Content-Type': undefined
},
data: { test: 'test' }
}
$http(req).then(function(){...}, function(){...});
You can set different headers for each of your $http calls !
you can still use http interceptor with check on request url
function HttpInterceptor() {
var interceptor = {
request: function (request) {
if (request.url === 'request_url1' || request.url === 'request_url2'){
request.headers['custom_header'] = 'this is conditional header';
}
return request;
},
response: function (response) {
console.log(response);
return response;
}
};
return interceptor;
}
Related
I have the following code which works when I run it as a local serverless function with netlify dev, but I need it to run cross origin from a dev server to the hosted server function. I put the function in a aws lambda function but I am getting a cross origin blocked error on my https:dev.website.com, I thought I have the correct headers in the return object so not sure why I am getting a cross origin error.
Any help would be great
const sanityClient = require("#sanity/client");
const client = sanityClient({
projectId: "random-id",
dataset: "production",
useCdn: true,
});
exports.lambdaHandler = async (event, context) => {
var body = JSON.parse(event.body);
//console.log(body.price_id)
try {
const checkPriceId = async (test) => {
const query = `*[_type == "products" && price_id == "${body.price_id}"]`;
const documents = await client.fetch(query, {}); // this could throw
return documents.map((document) => document.sold);
};
var ok = checkPriceId().then((test) => {
return new Promise(function (resolve, reject) {
//console.log(test) // this will log the return value from line 7
console.log(test);
resolve(test);
});
});
var bools = await ok;
// prettier-ignore
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods':'GET, POST, OPTION',
},
body: JSON.stringify({
sold: bools,
}),
};
} catch (err) {
return { statusCode: 500, body: err.toString() };
}
};
This is my request to the function if that helps
var fetchUrl = https://random.executue-api.aws.com/prod/sold //not exact
var fetchData = async function () {
const response = await fetch(fetchUrl, {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
price_id: final,
}),
})
.then(res => {
return res.json()
})
.catch(error => console.log(error))
return response
}
Update:
I tried adding cors the way suggested in the answer below, but it failed seen below so I tried manually adding the method response seen after.
I still get a cross domain error. And I have changed the domain so it is now https as well. Really stuck here.
I was looking into this more, and it seems like before it does the actual post it does a cors check at the options method, so I added in the same access control headers, and deployed but did not work. Don't quite get this.
Your headers look ok to me. (note: If you mix HTTP and HTTPS you are most likely to get a mixed content error in the client). If it is ONLY a CORS issue that you are seeing in the console in the web browser, then you might not have configured the API Gateway correctly in AWS.
In AWS, go to API Gateway and you should see something like the below:
Make sure that you enable CORS and then redeploy.
UPDATE:
Just looking at a previous implementation of a lambda function I setup with AWS. The headers I declared were as follows:
headers: {
"Content-Type" : "application/json",
"Access-Control-Allow-Origin" : "*",
"Allow" : "GET, OPTIONS, POST",
"Access-Control-Allow-Methods" : "GET, OPTIONS, POST",
"Access-Control-Allow-Headers" : "*",
"Access-Control-Allow-Credentials" : true
}
Your headers look OK to me though. However, when you created the method in the API Gateway, did you select Use Proxy Lambda Integration? (see screenshot).
Your client side fetch request looks ok. For reference mine was:
const url = 'your url';
const options = {
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
};
fetch(url, options).then(res => res.json());
Unrelated to this issue, but its not advisable to mix Async/Await with .then promise chaining. But this isn't the issue you are having. Just something to note.
Check the values from your Integration Response / try setting them manually for both OPTIONS and POST (and if that works, make sure you are passing through the response correctly from the lambda).
Your POST action should only require the Access-Control-Allow-Origin header. The other two (Access-Control-Allow-Methods, Access-Control-Allow-Headers) belong in the OPTION action. See this writeup, and note the full example exchange for a preflighted request (in grey): https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests
I am trying to create an interceptor for fetch in javascript (React to be more specific). It should get the result from every fetch that gets called, and if it is an 401 error it should initiate a new fetch call to another route to get a cookie (a refresh token). Then, the original fetch call should be tried again (because now the user is logged in).
I have managed to trigger the new fetch call and send back the cookie for each, but I got these two problems below:
I do not now how to retry the fetch call after the refresh token has been recieved. Is that possible? I found the fetch-retry npm (https://www.npmjs.com/package/fetch-retry) but not sure how and if I can implement that on an interceptor when it should be done for the original fetch call.
I seem to be doing something wrong with async await (I think), because the intercept is not waiting for the fetch call before returning the data (the statuscode on the original fetch seems to be 401 and not 200 which it should be after we get the cookie. I also tried to return the response of the fetch inside the interceptor but that returned undefined).
Any idea about how to solve this? Anyone who have done something similar?
Below is my code:
(function () {
const originalFetch = fetch;
fetch = function() {
return originalFetch.apply(this, arguments).then(function(data) {
if(data.status === 401) {
console.log('not authorized, trying to get refresh cookie..')
const fetchIt = async () => {
let response = await fetch(`/api/token`, {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
});
}
fetchIt();
}
return data
});
};
})();
EDIT: To make it more clear what I am after. I need an interceptor like I described above to work so I don't have to do something like this after every fetch call:
getData() {
const getDataAsync = async () => {
let response = await fetch(`/api/loadData`, { method: 'POST' });
if(response.status === 401) {
let responseT = await fetch(`/api/token`, {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
});
if(responseT.status === 401) {
return responseT.status
}
if(responseT.status === 200) {
response = await fetch(`/api/loadData`, { method: 'POST' });
}
}
let data = await response.json();
//Do things with data
};
getDataAsync();
};
So basically the interceptor should:
Check if there is a 401, if so then:
fetch api/token
If api/token returns 401, it should just return that.
If api/token returns 200, it should run original fetch again
You can simple use originalFetch for token and await for response if response is 401 then you simply return empty response to first fetch call else you updated token and then let it go to next condition which will rerun old request.
let TEMP_API = {
'401': {
url: 'https://run.mocky.io/v3/7a98985c-1e59-4bfb-87dd-117307b6196c',
args: {}
},
'200': {
url: 'https://jsonplaceholder.typicode.com/todos/2',
args: {}
},
'404': {
url: 'https://jsonplaceholder.typicode.com/todos/1',
args: {
method: "POST",
credentials: "include"
}
}
}
const originalFetch = fetch;
fetch = function() {
let self = this;
let args = arguments;
return originalFetch.apply(self, args).then(async function(data) {
if (data.status === 200) console.log("---------Status 200----------");
if (data.status === 401) {
// request for token with original fetch if status is 401
console.log('failed');
let response = await originalFetch(TEMP_API['200'].url, TEMP_API['200'].args);
// if status is 401 from token api return empty response to close recursion
console.log("==========401 UnAuthorize.=============");
console.log(response);
if (response.status === 401) {
return {};
}
// else set token
// recall old fetch
// here i used 200 because 401 or 404 old response will cause it to rerun
// return fetch(...args); <- change to this for real scenarios
// return fetch(args[0], args[1]); <- or to this for real sceaerios
return fetch(TEMP_API['200'].url, TEMP_API['200'].args);
}
// condition will be tested again after 401 condition and will be ran with old args
if (data.status === 404) {
console.log("==========404 Not Found.=============");
// here i used 200 because 401 or 404 old response will cause it to rerun
// return fetch(...args); <- change to this for real scenarios
// return fetch(args[0], args[1]); <- or to this for real scenarios
return fetch(TEMP_API['200'].url, TEMP_API['200'].args);
sceaerios
} else {
return data;
}
});
};
(async function() {
console.log("==========Example1=============");
let example1 = await fetch(TEMP_API['404'].url, TEMP_API['404'].args);
console.log(example1);
console.log("==========Example2=============");
let example2 = await fetch(TEMP_API['200'].url, TEMP_API['200'].args);
console.log(example2);
console.log("==========Example3=============");
let example3 = await fetch(TEMP_API['401'].url, TEMP_API['401'].args);
console.log(example3);
})();
Example1 request made to api for 404 status which will cause the 404 condition to run which will then call 200 api after which response will be returned
Example2 request made to 200 api which will return 200 status code which will cause 200 condition to pass and run and return response
Example3 request made to api for 401 status which will cause 401 condition to pass which will then call 200 api and print response after which it will fall out of condition where you can set token which will then be used in another fetch request
Try retuning the fetch promise instead of awaiting that.
(function () {
const originalFetch = fetch;
fetch = function () {
return originalFetch.apply(this, arguments).then(function (data) {
if (data.status === 200) console.log("---------Status 200----------");
if (data.status === 404) {
console.log("==========404 Not Found.=============");
return fetch(`https://jsonplaceholder.typicode.com/todos/2`);
} else {
return data;
}
});
};
})();
function test(id) {
//will trigger 404 status
return fetch(`https://jsonplaceholder.typicode.com/todos/` + id, {
method: "POST",
credentials: "include",
});
}
test(1).then((i) => console.log(i));
Interceptor library for the native fetch command. It patches the global fetch method and allows you the usage in Browser, Node and Webworker environments.
fetch-retry It wraps any Fetch API package (eg: isomorphic-fetch, cross-fetch, isomorphic-unfetch and etc.) and retries requests that fail due to network issues. It can also be configured to retry requests on specific HTTP status codes.
Im trying to make an HTTP request using fetch, but it's blowing up with the error: "SyntaxError: Unexpected token { in JSON at position 169681". This is my request function:
async getOportunidades() {
try {
const response = await fetch('https://gcsupport.internal.vodafone.com/bpa/webservices/GCCRM.asmx/GetCardsLeadsList',
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: 'POST',
body: JSON.stringify({userId: 29188,tipoAplic:'T'})
});
const data = await response.json();
this.listaOportunidades = data;
return data
} catch(e) {
console.log(e);
}
}
Looking at the response at Chrome developer tools all seems fine:
and after inspecting it seems I am receiving my json data as expected, and the json string is well formed, but for some reason it "breaks" on position 169681.
Is there like a size limit on the response?!
Just for the sake of my sanity I tried to make the same request using Jquery AJAX and everything runs fine!! Thing is, I don't want to use Jquery on my project. Anyone more experienced with Fetch has any idea why this is happening?
*********MY AJAX CALL********
$.ajax({
url:'https://gcsupport.internal.vodafone.com/bpa/webservices/GCCRM.asmx/GetCardsLeadsList',
type: 'POST',
data: {userId: 29188, tipoAplic: 'T'},
success: function(data) {
console.log(data)
},
error: function(xhr, status, error) {
console.log(xhr, status, error)
}
})
******webservice code*******
Sorry if this is a duplicate question but all the issues I could find were related to "Unexpected token < at position 0" which is not my case.
Thanks in advance
Cheers
Your web service is not handling JSON requests correctly. I've created a fetch example below that uses form data that should work. $.ajax interprets the object given as form data which is why it works.
What's happening is that your web service outputs BOTH data generated from JSON body and form data. It needs to be fixed to immediately return after handling JSON body, and not continuing to try to interpret form data (which in the case of a JSON body is blank).
tl;dr Web service is bugged. Does not end writing response after using JSON body data to generate response. So, after .write(responseFromJSONData()) it doesn't return and break, and tries to continue to .write(responseFromFormData([blankFormData])), resulting in two JSON objects being attached to your response.
async getOportunidades() {
try {
const response = await fetch('https://gcsupport.internal.vodafone.com/bpa/webservices/GCCRM.asmx/GetCardsLeadsList',
{
headers: {
'Accept': '*/*',
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
method: 'POST',
body: new URLSearchParams({userId: 29188,tipoAplic:'T'})
});
const data = await response.json();
this.listaOportunidades = data;
return data
} catch(e) {
console.log(e);
}
}
var data = JSON.stringify({"userId":29188,"tipoAplic":"T"});
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", "https://gcsupport.internal.vodafone.com/bpa/webservices/GCCRM.asmx/GetCardsLeadsList");
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(data);
Try this one.
I am basicly using 3 diffrent JS methods to get the data from the api but they return the error 405: Method Not Allowed but server has the get method in it as allowed. It is using path for the variable so I am wondering if it is related to that.
Here are the Codes for Methods that i call the API.
Fetch Method;
function getCompleted(queryParam) {
$('#loader').removeClass('hidden');
$('#loaded').addClass('hidden');
fetch("****/fullprofile/" + queryParam, {
method: "GET", headers: {
"User": "*****",
"Content-Type": "application/json"
}
})
.then((data) => {
const contentType = response.headers.get('content-type');
console.log(contentType);
return data.json()
})
.then(function (result) {
ResponseBody = result;
$('#loader').addClass('hidden');
$('#loaded').removeClass('hidden');
}).catch(function () {
$('#loader').addClass('hidden');
$('#loaded').removeClass('hidden');
});
}
HTTP Request Method;
function httprequest(queryParam2) {
$('#loader').removeClass('hidden');
$('#loaded').addClass('hidden');
var xmlhttp = new XMLHttpRequest();
xmlhttp.withCredentials=true;
var url = "*****/fullprofile/";
xmlhttp.onreadystatechange = function (data) {
console.log(this.responseText);
console.log(data);
}
xmlhttp.open("GET", url + queryParam2);
xmlhttp.setRequestHeader("User", "*****");
xmlhttp.send();
}
Ajax Method;
function ajax(queryParam3) {
$.ajax({
url: "****/fullprofile/" + queryParam3,
"method":"GET",
"headers":{
"User":"EBT\\****"
},
success: function (data) {
ResponseBody = data;
console.log(data);
}
});
}
Thank you all for the advices and help.
the reason was sending with headers; it returns options that needs to be responded again and it wasn't worth doing in JS so i decided to make a gateway api to use the api i have with header.
Thank you.
It is possible that the resource you are trying to consult does not use the verb GET.
you have to confirm with which verb the resource is obtained
Look here:
405 Method Not Allowed MDN Docs
Confirm in the documentation of the api with which verb that resource is requested. I could be POST, PUT etc
Here you can look explanation
If i have one API server then the API is send ajax data with JSON format :
{"status":304,"message":"Cannot delete data where PK is empty or > 1"}
how to AngularJS $http post call the status and message to alert bootbox?
here my AngularJS $http post
$http({
method: "POST",
url: apiUrl('disable_assethw'),
data: {
id: id
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function successCallback(response) {
if(response.status == 304) {
bootbox.alert("Something went error.." + response.data.message);
} else {
$scope.getAssetHW();
}
}, function errorCallback(response) {
bootbox.alert("Something went error.." + response.status);
});
thanks for advise.
When doing a POST request with JavaScript objects as data, use the AngularJS default content type (which is automatically set to application/json). The $http service also automatically encodes JavaScript objects as JSON strings.
Only response with status in the range 200-299 are processed by the success handler. Status outside the range are processed by the rejection handler:
$http({
method: "POST",
url: apiUrl('disable_assethw'),
data: {
id: id
},
headers: {
̶'̶C̶o̶n̶t̶e̶n̶t̶-̶T̶y̶p̶e̶'̶:̶ ̶'̶a̶p̶p̶l̶i̶c̶a̶t̶i̶o̶n̶/̶x̶-̶w̶w̶w̶-̶f̶o̶r̶m̶-̶u̶r̶l̶e̶n̶c̶o̶d̶e̶d̶'̶
}
}).then(function successCallback(response) {
̶i̶f̶(̶r̶e̶s̶p̶o̶n̶s̶e̶.̶s̶t̶a̶t̶u̶s̶ ̶=̶=̶ ̶3̶0̶4̶)̶ ̶{̶
̶b̶o̶o̶t̶b̶o̶x̶.̶a̶l̶e̶r̶t̶(̶"̶S̶o̶m̶e̶t̶h̶i̶n̶g̶ ̶w̶e̶n̶t̶ ̶e̶r̶r̶o̶r̶.̶.̶"̶ ̶+̶ ̶r̶e̶s̶p̶o̶n̶s̶e̶.̶d̶a̶t̶a̶.̶m̶e̶s̶s̶a̶g̶e̶)̶;̶
̶}̶ ̶e̶l̶s̶e̶ ̶{̶
$scope.getAssetHW();
̶}̶
}, function errorCallback(response) {
//HANDLE 304 status HERE
if(response.status == 304) {
bootbox.alert("Something went error.." + response.data.message);
} else {
bootbox.alert("Something went error.." + response.status);
};
});
From the Docs:
A response status code between 200 and 299 is considered a success status and will result in the success callback being called. Any response status code outside of that range is considered an error status and will result in the error callback being called. Also, status codes less than -1 are normalized to zero. -1 usually means the request was aborted.
— AngularJS $http Service API Reference
Note: A status of -1 usually indicates the browser rejected the request with a CORS problem that violates same-origin policy.
you said it is json response and you used: application/x-www-form-urlencoded , which is wrong.
The best practice to handle rest/api call is:
Create 1 common/general function which is accessible in whole application which will manage your post api call(add api response to callback):
postAPICall(url, body, data) {
let headers = new Headers({'Content-Type': 'application/json'});
this.http
.post(url,
body, {
headers: headers
})
.map(
response => response.json())
.subscribe(
response => {
data(response);
},
err => data(this.handleError(err)); //handle error here
);
}
call this function wherever required(in component or service):
var yourJSONBody = {
"param-1": "",
"param-2": "",
//....
}
}
this.myCommonService.postAPICall("localhost:8080/app/", yourJSONBody, data => {
if (data.status == "304") {
//do stuff
//this.msgs.push({severity: 'error', detail: data.message});
}
else {
//do stuff
}
});
error handler function:
private handleError(error: any) {
let description = 'There was an error: ' + error.status;
let errors = {
errorcode: error.status,
errorstatus: error.statusText,
errordescription: description
};
return errors;
}