Xhttp request always returns a 0 response code. - While making a post request using form data - react-native

I am trying to upload an array of images using form data and xhttp.
Client : React Native - Both platforms
Server : Node running on GCP
Images go into s3.
Problem : Images are uploaded into s3. And when i look at my server logs i see the server is sending 200.
But, client is always receiving response code 0.
And also xhttp goes from state 1 -> 4.
We have added CORS on both ends so that might not be an issue.
I have accept and content headers. But, no idea what's going wrong.
Any help is appreciated.
React-Native Client:
upload()
{
let url = "MYAPIGOESHERE"
let uploadBody = new FormData()
let imagesUpload = []
imagesUpload.push({type:'image/jpg',uri:this.state.coverImage[0].uri,name:"cover"})
uploadBody.append('photos',{uri:this.state.coverImage[0].uri, type:'image/jpg', name:"cover"})
uploadBody.append('duration',this.state.duration)
var xhttp = new XMLHttpRequest()
xhttp.onreadystatechange = function() {
console.log(this.readyState+" "+this.statusText)
if (this.readyState === 4) {
alert(this.status)
if (this.status === 200) {
console.log(this.responseText);
} else {
console.log(this);
}
}
if(this.readyState === 3)
{
console.log("Inside 3")
}
if(this.readyState === 2)
{
console.log("Inside 2")
}
};
xhttp.open("POST", url)
xhttp.setRequestHeader('Accept', 'application/json');
xhttp.setRequestHeader('Access-Control-Allow-Origin', '*');
xhttp.responseType = 'json'
xhttp.send(uploadBody)
}

Related

Is there a way to execute XHR Requests via VS Code Extension?

I am building a VS Code extension and in that, I need to execute an XHR Request to my server to fetch some data.
I tried using this in my code :
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
vscode.window.showInformationMessage(this.responseText);
}
};
xhttp.open("GET", "https://reqres.in/api/users?page=2", true);
xhttp.send();
}
but it is showing an error :
Any idea, how can I achieve my goal?
XMLHttpRequest and fetch are only available in the browser. vsCode is node.js based. Use Axios instead. How can I make a POST request in a VSCode extension

Shutdown Kodi with api (blackberry qml)

Hello I trying shutdown Kodi (raspberry pi) with mobile app (blackberry qml).
But I do not how.
I used this code: (in browser)
"http://[myip]:[myport]/jsonrpc?request={"jsonrpc":"2.0","method":"System.Suspend","id":1}"
I used this code: (in the app)
function sendRequest() {
var xhr = new XMLHttpRequest();
var url = "http://[myip]:[myport]/jsonrpc?request={\"jsonrpc\":\"2.0\",\"method\": \"System.Suspend\",\"id\":1}"
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
console.log(xhr.responseText);
textArea.text = xhr.responseText;
}
}
};
xhr.open("GET", url, true); // with "POST" I got the same problem.
xhr.send();
}
I got:
{"error":{"code":-32700,"message":"Parse error."},"id":null,"jsonrpc":"2.0"}
Remote from web browser works fine (http://[myip]:[myport])
Thank you for your answers.
********** Update: 21.10.2020 **********
I'm in progress. But I don't know what to do next.
I found some information why I have an error.
I don't know how to implement in my code.
Can you help me?
Thank you so much.
https://github.com/xbmc/xbmc/pull/12281
https://forum.kodi.tv/showthread.php?tid=324598&highlight=json
Here's how to do it.But I can't understand it.
https://retifrav.github.io/blog/2018/09/01/kodi-remote-control-app/
This is my function (on Kodi 17.6 it is working but on Kodi 18 is not working )
function sendRequest() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
text.text = xhr.responseText
}
}
};
var url = 'http://<IP:PORT>/jsonrpc?request={"jsonrpc": "2.0", "id": 1, "method": "System.Shutdown"}'
xhr.open("GET", url, true) // when I write "POST" - nothing happens
xhr.send()
}
You should URL encode the json in your url before it's used in the open method. Use encodeURIComponent() to do that. Your browser is changing:
{"jsonrpc":"2.0","method": "System.Suspend","id":1}"
To:
%7B%22jsonrpc%22%3A%222.0%22%2C%22method%22%3A%20%22System.Suspend%22%2C%22id%22%3A1%7D%22
But your code is not.

does the data sent to the server using http Post update the servers API url?

Im a newbie to flutter so please if you think the question context is wrong update it, im fetching a data from an SQl server to my flutter app, and i also want to send the users info back to the server after they fill out a form, im using the http.post and i get the response’s body correctly but when i open the Server Url (api url) i dont see it updated with the new info i posted to it, can someone please tell me how Post is supposed to work?
I'm new to Flutter too, this is a working example of how i understand it
class HttpService {
createUser(String name, String lastname) async {
Map data = {'name': name, 'lastname': lastname};
var body = json.encode(data);
var jsonResponse = null;
var response = await http.post(serverUrl + "/create/",
headers: {
HttpHeaders.authorizationHeader: '**Token_here_if_you_use_it**',
HttpHeaders.contentTypeHeader: "application/json",
}, body: body);
jsonResponse = json.decode(response.body);
if (response.statusCode == 201) {
jsonResponse = json.decode(response.body);
if (jsonResponse != null) {
print(jsonResponse.toString());
}
} else {
print(jsonResponse.toString());
}
}
}
In your main.dart :
final HttpService httpService = HttpService();
httpService.createUser(name,lastname);

API Request in Dialogflow Fulfillment (Javascript)

So I'm trying to make a google action using Dialogflow that requires an external API. I've always used jQuery .getJSON() to make API calls, so I had no idea how to do this. After searching this up online, I found a way to do this using vanilla javascript (I also tested the way on my website and it worked fine). The code for that is below:
function loadXMLDoc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
console.log(xmlhttp.responseText);
}
};
xmlhttp.open("GET", "https://translate.yandex.net/api/v1.5/tr.json/translate?lang=en-es&key=trnsl.1.1.20190105T052356Z.7f8f950adbfaa46e.9bb53211cb35a84da9ce6ef4b30649c6119514a4&text=eat", true);
xmlhttp.send();
}
The code worked fine on my website, but as soon as I added it to the Dialogflow, it would give me the error
XMLHttpRequest is not defined
Obviously that happened because I never defined it (using var), except it worked without me doing anything. So then, I tried adding this line
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
to the code, and it stopped giving me the error (because I defined XMLHttpRequest). But then, my code wouldn't work.
TL;DR: How can I make an external API call using Dialogflow fulfillment?
You can use https. But make sure that you upgrade to Blaze Pay(or any other plans) to make external API calls, else you will receive an error such as
Error:
Billing account not configured. External network is not accessible and quotas are severely limited. Configure billing account to remove these restrictions.
Code to make external api call,
// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
"use strict";
const functions = require("firebase-functions");
const { WebhookClient } = require("dialogflow-fulfillment");
const { Card, Suggestion } = require("dialogflow-fulfillment");
const https = require("https");
process.env.DEBUG = "dialogflow:debug"; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(
(request, response) => {
const agent = new WebhookClient({ request, response });
console.log(
"Dialogflow Request headers: " + JSON.stringify(request.headers)
);
console.log("Dialogflow Request body: " + JSON.stringify(request.body));
function getWeather() {
return weatherAPI()
.then(chat => {
agent.add(chat);
})
.catch(() => {
agent.add(`I'm sorry.`);
});
}
function weatherAPI() {
const url =
"https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22";
return new Promise((resolve, reject) => {
https.get(url, function(resp) {
var json = "";
resp.on("data", function(chunk) {
console.log("received JSON response: " + chunk);
json += chunk;
});
resp.on("end", function() {
let jsonData = JSON.parse(json);
let chat = "The weather is " + jsonData.weather[0].description;
resolve(chat);
});
});
});
}
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
let intentMap = new Map();
intentMap.set("Default Welcome Intent", welcome);
intentMap.set("Default Fallback Intent", fallback);
intentMap.set("Weather Intent", getWeather);
agent.handleRequest(intentMap);
}
);
This article is a diamond! It really helped to clarify what's going on and what's required in Dialogflow fullfilments.
A small suggestion is to gracefully catch the error in the connection to the webservice:
function weatherAPI() {
const url = "https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22";
return new Promise((resolve, reject) => {
https.get(url, function(resp) {
var json = "";
resp.on("data", function(chunk) {
console.log("received JSON response: " + chunk);
json += chunk;
});
resp.on("end", function() {
let jsonData = JSON.parse(json);
let chat = "The weather is " + jsonData.weather[0].description;
resolve(chat);
});
}).on("error", (err) => {
reject("Error: " + err.message);
});
});
}

Direct Upload to S3 from the browser with Authorization Signature Ver 4

I need to upload a file to S3 directly from the browser. In the beginning I created a script that is working but to authorize I need to put my credentials accessKeyId and secretAccessKey, what it is not secure.
I figured out that I can use for authorization the "Authorization Signature"
It seems great but I can't find where I can put this authorization header to the request in the upload() method.
An example of my authorization header:
Authorization: AWS4-HMAC-SHA256
Credential=/20151016//s3/aws4_request,
SignedHeaders=content-type;host;x-amz-date,
Signature=4eee344a71a58623febc4079024a27cb62f3d26546695422244fcefe50d0168d
Thanks for your advice.
I have found solution for this issue. My solution is based on example from this site.
In final solution I don't use javascript SDK, it is using post form with authorization inputs what is sending with post parameters.
You can enclose a signed policy document with your POST request in order to authenticate securely, with AWS Signature Version 4.
If you're on Node, you can use the aws-s3-form package on the server to generate the necessary form data your client requires in order to send a successful request to S3.
You might want to read my blog post on the subject for full insight.
Example Server Side Code (Node)
let AwsS3Form = require('aws-s3-form')
[...]
// A hapi.js server route
server.route({
method: ['GET',],
path: '/api/s3Settings',
config: {
auth: 'session',
handler: (request, reply) => {
let {key,} = request.query
let keyPrefix = `u/${request.auth.credentials.username}/`
let region = process.env.S3_REGION
let s3Form = new AwsS3Form({
accessKeyId: process.env.AWS_ACCESS_KEY,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region,
bucket,
keyPrefix,
successActionStatus: 200,
})
let url = `https://s3.${region}.amazonaws.com/${bucket}/${keyPrefix}${key}`
let formData = s3Form.create(key)
reply({
bucket,
region,
url,
fields: formData.fields,
})
},
},
})
Example Client Side Code
let R = require('ramda')
let ajax = require('./ajax')
class S3Uploader {
constructor({folder,}) {
this.folder = folder
}
send(file) {
let key = `${this.folder}/${file.name}`
return ajax.getJson(`s3Settings`, {key,})
.then((s3Settings) => {
let formData = new FormData()
R.forEach(([key, value,]) => {
formData.append(key, value)
}, R.toPairs(s3Settings.fields))
formData.append('file', file)
return new Promise((resolve, reject) => {
let request = new XMLHttpRequest()
request.onreadystatechange = () => {
if (request.readyState === XMLHttpRequest.DONE) {
if (request.status === 200) {
resolve(s3Settings.url)
} else {
reject(request.responseText)
}
}
}
let url = `https://s3.${s3Settings.region}.amazonaws.com/${s3Settings.bucket}`
request.open('POST', url, true)
request.send(formData)
})
}, (error) => {
throw new Error(`Failed to receive S3 settings from server`)
})
}
}