Axios get response headers. Works in node, not in react - node.js

I will start off by saying this has nothing to do with authentication of JWT tokens.
I am trying to pull data from a public api. Lets call it www.abc.com/WeatherAPI.
When I do this in node with axios using axios.get(url), I am able to console.log(res.headers) and they show perfectly.( I need them for pagination and a recursive function)
When I use the EXACT SAME code in react, I get empty headers returned....
eg: content-type: "application/json"
date: "Sun, 08 Mar 2020 09:23:03 GMT"
Code:
return axios
.get(
'https://api.xxxxxxxx' +
(cursor ? '&cursor=' + cursor : '')
)
.then(res => {
console.log(res);
console.log(res.headers['cursor']);
// If there is no data, return...
if (res.data.length < 1) return;
// Push current data into OB state
setOB({ ...oB, ...res.data });
//te
//If there is no cursor... ie there is no more data, return
if (!res.headers['cursor']) return;
return OB(res.headers['cursor']);
});
};
// I dont know if use effect is right here... we will see..
useEffect(() => {
OB();
}, []);`

as the API is public, it could be that the response header differs based on the agent. it is not likely to be the case but it can be. I would suggest overriding the headers object including the User-Agent
axios.get(
`https://api.xxxxxxxx${cursor ? '&cursor=' + cursor : ''}`,
{ headers: { 'User-Agent': 'YOUR-SERVICE-NAME' } },
).then()...

Related

Cant`t insert Cyrillic symbols in POST fetch URL - NodeJS

Working on Telegram bot. A user sends requests from the bot to an external website API to get information. The very usual stuff.
I'm trying to make a POST request from NodeJS (Express) backend which contains cyrillic symbols
https://somewebsite.ru/api/v1/order.json?orderId=**МУЗ**008134
it says: TypeError [ERR_UNESCAPED_CHARACTERS]: Request path contains unescaped characters
Then I was trying to use ${encodeURIComponent(orderNumber)} instead of ${orderNumber}
Error checnged to
FetchError: invalid json response body at https://somewebsite.ru/api/v1/order.json?orderId=%D0%9C%D0%A3%D0%97008058 reason: Unexpected end of JSON input
When I use Postman there is no problem. I just put the whole URL https://somewebsite.ru/api/v1/order.json?orderId=МУЗ008134 and it works fine.
the server has utf8 encoding.
I'm using WebStorm and VS Code - both are set with UTF8
Here is the code:
oneOrder: async (orderNumber) => {
try {
let url = `https://somewebsite.ru/api/v1/order.json?orderId=${orderNumber}`
return fetch(url, {
method: 'post',
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
})
.then(res => res.json())
.then(answer => {
if (answer.error) {
return answer.message
} else if (answer.orderId) {
return `Номер заказа: ${answer['orderId']}\nСоздан ${answer['createdAt']}\nОбщая стоимость товаров в заказе: ${answer['totalCost']}\nСтатус оплаты: ${answer['status']['payment']}\nСтатус доставки: ${answer['status']['delivey']}`
}
return 'Нет информации по заказу'
})
} catch (e) {
console.log('ERROR with oneOrder function:', e)
}
},
...and, by the way, I have no idea why the "МУЗ008134" is not showed as a part of URL, but as a ppendix to the URL.
Thanks a lot and sorry if it seems to be too obvious.

How can response header can be modified?

i have a problem that break my mind since 2 days.
request( {url: url } , function(err,res, body){ res.headers['...'] = ...; return res }).pipe(response);
I thought this code change the header from the first response then put him on the second response. but NOT, all attempt fail. I try and I try but NOTHING, NOTHING WORKK.
Look, I'm really in peace and open-minded.
that's my code clear and concise :
modify_header(err,res,body){
var header = res.headers;
header['x-frame-options'] = null;
header['Set-Cookie'] = 'HttpOnly;';
return res;
}
request_src(req,response){
let isabsolute = this.decode_href(req.url);
if(!isabsolute) {
request.get({ url : this.url+req.url , headers : this.headers },this.modify_header).pipe(response);
}else{
request.get({ url : isabsolute , headers : this.headers },this.modify_header).pipe(response);
}
return false;
}
request_src(req,response) is a function called in http.createServer so, req & response are just the request from clients.
then, when i do request.get( {url:this.url ... I send client's request to an another site, like a proxy. but i need to change the header between the "other site" and the client. and believe me for sure, function modify_header modify nothing.
no, i lie just a little, when i set header['x-frame-options'] = null;res.headers is equals to null. that's ok
BUT, in the browser (client side) It just doesn't work that way. 'x-frame-options' is deny or something that's not mine (the same for cookie).
can you help me please, I pull out my hair since 2 days and this isn't good for me.
thank you.
The issue is that callbacks actually happen after a request is complete, which is way after the pipe has already begun streaming data to the response. You probably want to hook into the response event, which would look something like this:
request.get({ url: this.url + req.url, headers: this.headers })
.on('response', function (resp) {
resp.headers['my-custom-header'] = 'blah';
})
.pipe(response);
The response event is emitted before streaming to the destination (which in this case, is back to the original caller), so you should be able to do what you want using this method.
my code looks like that right now :
modify_header(res){
var header = res.headers;
header['x-frame-options'] = null;
header['Set-Cookie'] = 'HttpOnly;';
return res;
}
request_src(req,response){
console.log('original: ',req.url);
let isabsolute = this.decode_href(req.url);
if(!isabsolute) {
request.get({ url : this.url+req.url , headers : this.headers })
.on('response',this.modify_header)
.pipe(response);
}else{
request.get({ url : isabsolute , headers : this.headers})
.on('response',this.modify_header)
.pipe(response);
}
return false;
}

HttpClientModule http.get not working

I picked up this previous working app (Angular2) and find that it is not working (Angular4) as expected now.
Module was used (it may not matter):
import { HttpModule, JsonpModule } from '#angular/http';
Module being used now:
import { HttpClientModule} from '#angular/common/http';
Trying to get a list of records from the backend (Node.js, Express, and MongoDB) as below.
listResource(resType: string, parameters: string[]) {
console.log("***listResource");
let headers = new HttpHeaders().set("X-CustomHeader", "custom header value");
headers.append('Content-Type', 'application/fhir+json');
headers.append("'Access-Control-Allow-Origin", "*");
headers.append("Accept", "application/fhir+json");
headers.append("USER_KEY", "QIF83Fjoe4sYxdQsah3h"); //TOUCHSTONE KEY
let urlString = this.baseUrl + resType + "/list"; // + queryString;
console.log("List resource URL string: [" + urlString + "]");
return (this.httpClient.get(urlString, { headers })
.map((res: Response) => res.json()))
.catch((error: any) => Observable.throw(error.json().error || 'Server error from Observable http.get call')); //...errors if any
}
when my component is loaded, the above listResource will be called as below.
ngOnInit() {
//Get the initial 25 latest patient
//this.progressBar = true;
this.currentPage = 0;
this.patientList = [];
this.globalSvc.gPatient = [];
console.log("***OnInit");
this.restSvc.listResource("Patient", ["identifier=*", "family=*", "given=*"]).subscribe(
data => {
console.log("Response data: " + JSON.stringify(data));
},
(err: HttpErrorResponse) => {
if (err.error instanceof Error) {
// A client-side or network error occurred. Handle it accordingly.
console.log('An error occurred:', err.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.log(`Backend returned code ${err.status}, body was: ${err.error}`);
}
});
}
Below is the output from Chrome console. Of course, I don't get any good response. It seems to me the Chrome browser sends CORS option and the server responds correctly, then the browser doesn't send the actual GET.
If I send the REST API request from PostMan directly which doesn't have CORS, I get the expected good response from the server. Hence, it seems to me the server is ok.
Questions:
Any idea how to debug or fix it?
Will this relate to CORS on both Angular client and Node.js server?
The ${err.status} and ${err.error} are "undefined" in Chrome console. How can I find the actual error?
console.log(Backend returned code ${err.status}, body was: ${err.error});
Update 1 based on Grey's suggestion on the immutable header and const.
The GET is returning data now.
headers.append() does not alter the headers, it returns a new Headers (because Headers is immutable).
So, instead of
let headers = new HttpHeaders().set("X-CustomHeader", "custom header value");
headers.append('Content-Type', 'application/fhir+json');
headers.append("'Access-Control-Allow-Origin", "*");
headers.append("Accept", "application/fhir+json");
headers.append("USER_KEY", "QIF83Fjoe4sYxdQsah3h"); //TOUCHSTONE KEY
you need to do something like:
let headers = new HttpHeaders().set("X-CustomHeader", "custom header value")
.append('Content-Type', 'application/fhir+json')
.append("'Access-Control-Allow-Origin", "*")
.append("Accept", "application/fhir+json")
.append("USER_KEY", "QIF83Fjoe4sYxdQsah3h");
Oh, and that should actually be const headers =, rather than let headers =

Unable to access cookie value from onHeadersReceived

From this example I've use this code:
chrome.webRequest.onHeadersReceived.addListener(
function (details) {
details.responseHeaders.forEach(function(responseHeader){
console.log(responseHeader.name + "===" + responseHeader.value);
if (responseHeader.name.toLowerCase() === "set-cookie") {
responseHeader.value = processSetCookieStr(responseHeader.value);
}
});
return {
responseHeaders: details.responseHeaders
};
}, {
urls: ["*://*/*"]
}, ['blocking','responseHeaders']
);
But I'm not able to see any cookie in the headers.
For main_frame type I've printed the values but cookie isn't there:
Cache-Control===private
Content-Type===text/html; charset=utf-8
Server===Microsoft-IIS/7.5
X-AspNet-Version===4.0.30319
X-Powered-By===ASP.NET
Date===Sat, 29 Apr 2017 08:51:45 GMT
Content-Length===29880
Though I'm able to fetch the desired cookie using chrome.cookies.get
Why am I unable to access cookie info in the onHeadersReceived?
You should add "extraHeaders" to the third parameter of the webRequest listener and it should be ['blocking','responseHeaders', 'extraHeaders'] for your example.
Starting from Chrome 72, the Set-Cookie response header is not provided and cannot be modified or removed without specifying 'extraHeaders' in opt_extraInfoSpec.
Refer https://developer.chrome.com/docs/extensions/reference/webRequest/

difference between res.send or res.json

What is the difference between
res.status(STATUS_CODE).send({"message" : "this is the message" });
and
res.status(STATUS_CODE).json({"message" : "this is the message" });
although checked the similar question but that is in context of express 3 and I am looking for express 4
Ultimately, both will achieve the same thing. If you call res.send with an object, it will hit this switch in res.send:
switch (typeof chunk) {
// string defaulting to html
case 'string':
if (!this.get('Content-Type')) {
this.type('html');
}
break;
case 'boolean':
case 'number':
case 'object':
if (chunk === null) {
chunk = '';
} else if (Buffer.isBuffer(chunk)) {
if (!this.get('Content-Type')) {
this.type('bin');
}
} else {
return this.json(chunk);
}
break;
}
If the object you're sending it is not a Buffer - it will call res.json.
res.json simply sets the Content-Type header to application/json and runs the object through JSON.stringify - with specified replacer function and spacer value. Eventually it calls res.send.
This call of res.send is sent a string and the case statement will break resulting in the rest of the function being run. The remainder of the send function sets things like etag, content size etc. You can find out more by looking at the express code.
They start to differ when you send them non-object responses, such as strings, numbers etc. As in that case res.json will run it through JSON.stringify but res.send wont: resulting in different Content-Type headers and content.
edit: to answer your comment on the other answer, sending different status codes will still behave the same.
.json calls .toJSON() method on the object (if it exists) and also sets the content-type header to application/json
But basically you can simulate .json with .send, if you do the above manually.
For example this middleware
(req, res, next) => {
let x = {};
x.toJSON = () => {
console.log('oh yeah');
return 15;
};
return res.json(x);
}
Prints
oh yeah
And returns 15 to the request with these headers (at least in my simple express app):
Connection →keep-alive
Content-Length →2
Content-Type →application/json; charset=utf-8
Date →Wed, 08 Jun 2016 10:16:09 GMT
ETag →W/"2-m/Mcf/Bik2qW08i9H48v8w"
Vary →Accept-Encoding
X-Powered-By →Express

Resources