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

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.

Related

Why is node.js fetch giving a 'Bad Request' error?

I am getting a 400 error (bad request) from this POST:
siteData.myPost = async function (url, data) {
let options = {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(data)
}
try {
const response = await fetch(quilkinUrlBase() + url,options);
return response.json();
}
catch (error) {
qPopup.Alert("Error with web request: " + error);
}
};
(the fetch address computes to "http://localhost:1337/UpdateSiteVisits").
This can't, of course, convert 'response' to json because the response is a DOC containing the 400 error message.
in server.js I have the following callback definition for the URL specified in the fetch:
app.post("/UpdateSiteVisits", sites.updateVisits);
in the debugger, the code never reaches updateVisits().
I have a very similar construct with a GET:
app.get("/GetSitesForType/:type", sites.findByType);
which works fine, so I assume the problem is with the 'options' object (which the GET doesn't use). In the POST case the data is just an integer ID, and if I change the data format to plain text (instead of json), the post works fine.
If leave the format as json, and send an object, rather than a simple integer, the post also works fine. So it looks like the system just doesn't like converting a single integer to json.
I needed to send the integer as json, so instead of using the method like this:
siteData.myPost("UpdateSiteVisits", siteID)
I needed to use
siteData.myPost("UpdateSiteVisits", { siteId: siteID })
[ later ]
Please ignore my question and answer, I was just getting mixed up with types. Such is the result from me converting from strongly-typed C# to untyped javascript!

Getting error 400 when trying to use Azure Speech Recognition and Flutter

I've been given the task to use the Azure Speech Recognition API on a Flutter application. The app is supposed to record the user's voice and send it to the Azure API. I've tried to use the only pub.dev plugin that I could find, but it did not work and the documentation does not have a Flutter example. Since the request returned 200 on Postman and I was able to make it work on a Javascript application, the problem must be my Flutter application, maybe something on the request, since it is returning code 400 (bad request), saying that the request contains invalid data.
The code below is my request to the API. The file which I'm using to get the bytes is a wav file containing the recorded voice
Could you help me? Thanks for the attention.
var bytes = file.readAsBytesSync();
var response = await Dio().post(
"https://brazilsouth.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1?language=pt-BR",
data: bytes,
options: Options(
headers: {
"Ocp-Apim-Subscription-Key": "subscriptionKey",
"Content-Type": "audio/wav"
},
);
print(response.statusCode);
After trying to solve this problem for a couple of days, I finally got a successful response!
Future<dynamic> speechToText(File file) async {
final bytes = file.readAsBytesSync();
var headers = {
'Ocp-Apim-Subscription-Key': key,
'Content-Type': 'audio/wav'
};
var response;
Map<String, dynamic> responseBody;
var recognizedVoiceText;
try {
response = await http.post(
"https://brazilsouth.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1?language=pt-BR",
body: bytes,
headers: headers,
);
// The response body is a string that needs to be decoded as a json in order to extract the text.
responseBody = jsonDecode(response.body);
recognizedVoiceText = responseBody["DisplayText"];
} catch (e) {
print('Error: ${e.toString()}');
recognizedVoiceText = "Something went wrong";
}
return recognizedVoiceText;
}

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

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()...

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 =

Problems making http-post requests with German umlauts (ä ö ü) or special chars (ß) with Node.js

TLDR; solved, see comments below :)
I am really getting nuts with this: I want to post JSON to the Redmine API to send time entries imported via CSV files. Everything works well, until I try to send strings with German umlauts (ä ü ö) or special chars (ß).
I am using the request package with the following code:
var options = {
url: self.getHost() + path,
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
method: method
};
options.headers[self.getApiKeyHeader()] = self.getApiKey();
if (method !== HttpMethods.Get) {
params.time_entry.comments = 'äöüß';
options.body = JSON.stringify(params);
options.headers['Content-Length'] = options.body.length;
}
And send it like this:
request(options, function (error, response) {
if (response.statusCode === 201) {
console.log('Success');
}
else {
console.log('Error: ' + response.statusCode);
}
});
I always get an HTTP500 Error with server logs saying "Invalid byte sequence in UTF-8". I get the same error when I try to post the JSON via Postman. As my coworkers have no problems with Ruby and PHP script, I guess I got something terribly wrong in my script. Also tried the following alternatives for setting the options.body content:
options.body = new Buffer(JSON.stringify(params), encoding='utf8');
options.body = new Buffer(JSON.stringify(params, 'ascii').toString('utf8');
With both also not working.
I am using https://www.npmjs.com/package/request for the requests.
What am I doing wrong?

Resources