I'm trying to invoke an API call to an api published in an external machine, the api uses flask and has the annotation #crossOrigin, and I can reach it from my machine using postman, but when I try to call it from my code, I get the exception (failed to fetch), here's the code
let options ={
method: 'POST',
mode: 'cors',
headers: {
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Headers' : 'Origin, X-Requested-With, Content-Type, Accept'
},
body: data
};
const resp = await fetch('http://1.2.3.4:8555/api/v1/upload', options);
I also get the following syntax error in VSCode
Argument of type '{ method: string; mode: string; headers: { 'Access-Control-Allow-Origin': string; 'Access-Control-Allow-Headers': string; }; body: FormData; }' is not assignable to parameter of type 'RequestInit'.
Types of property 'mode' are incompatible.
Type 'string' is not assignable to type 'RequestMode'.ts(2345)
Related
I'm trying to GET some data from our business server using a GET request with Vue and Axios. I encounter a 401 unauthorized error however. I'm able to GET this data with RESTED when I log in with my company account. I've already looked at this post: How to send Basic Auth with axios but no solution worked for me. This is my code to make the get request:
await axios.get('http://192.168.*******', {}, {
auth: {
username: 'username',
password: 'password'
},
headers: {
'Content-Type': 'application/json'
}
});
}
I've also tried without the 'headers'. This is the error message:
xhr.js:214 GET http://192.******** 401 (Unauthorized)
dispatchXhrRequest # xhr.js:214
[Vue warn]: Unhandled error during execution of created hook
at <App>
createError.js:19 Uncaught (in promise) Error: Request failed with status code 401
at createError (createError.js:19:15)
at settle (settle.js:19:12)
at XMLHttpRequest.onloadend (xhr.js:75:7)
Hopefully someone has an idea because I'm at a loss.
This solution has worked for me:
const config = {
'Content-Type': 'application/json',
"Accept": "application/json",
}
const { data } = await axios({ url: 'http://192.168.170.*****/', method: 'GET', data: null, withCredentials: true, headers: config })
I have been banging my head against the wall for hours now... tried every type of combination to get this working.
I have my own API endpoint here: https://app.automate.mn/api/tools/email/add
Which I am trying to post data to from 3rd party websites.
app.js
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.options('*', cors());
...
const {addContact} = require('./routes/api/tools/email');
app.post('/api/tools/email/add', addContact);
addContact.js
addContact: async function (req, res) {
res.status(200).send('OK - TEST');
return;
}
I have setup a test website here with the form: https://demoautomatemn.wpcomstaging.com/
When you submit the form, it's posting the data to the endpoint:
loadForm.js
automate_post_data('https://app.automate.mn/api/tools/email/add', data)
.then(data => {
console.log(data); // JSON data parsed by `data.json()` call
});
async function automate_post_data(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
mode: 'cors', // no-cors, *cors, same-origin
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
//referrerPolicy: 'origin', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status} - ${response.statusText}`);
}
return response.json();
}
The post is failing:
Access to fetch at 'https://app.automate.mn/api/tools/email/add' from origin 'https://demoautomatemn.wpcomstaging.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
loadForm.js:109 POST https://app.automate.mn/api/tools/email/add net::ERR_FAILED
I was expecting to see the "Access-Control-Allow-Origin" in the response headers for the OPTION call but nothing (Preflight response is not successful). I have tried everything to get it working.
Any suggestions would be so welcome right now.
OK, Progress but no cigar!
I setup the following:
Setting at apache level:
https://docs.bitnami.com/bch/infrastructure/nodejs/administration/enable-cors-nodejs/
You might also find this helpful: https://enable-cors.org/server_apache.html
Adding origin to the request
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Origin': window.location.href
},
referrerPolicy: 'origin',
This then resulted in the error message changing:
Access to fetch at 'https://app.automate.mn/api/tools/email/add' from origin 'https://demoautomatemn.wpcomstaging.com' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
Update 'Content-Type': 'application/x-www-form-urlencoded',
As per this post: Why doesn't adding CORS headers to an OPTIONS route allow browsers to access my API?
I updated the request to x-www-form-urlencoded
const response = await fetch(url, {
method: method,
mode: 'cors', // no-cors, *cors, same-origin
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Origin': window.location.href
},
referrerPolicy: 'origin', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: data // body data type must match "Content-Type" header
});
It feels like progress however I am still getting 406 error:
POST https://app.automate.mn/api/tools/email/add 406
Response {type: "cors", url: "https://app.automate.mn/api/tools/email/add", redirected: false, status: 406, ok: false, …}
I don't know what I did wrong and need help.
function loadDoy() {
axios({
method: 'post',
headers: {
"Access-Control-Allow-Origin": "*",
'Content-Type': 'application/json',
},
url: apiPostUrl,
data: {
user: "webuser",
password: "m0nk3yb#rz",
layout: "Main Menu"
},
})
.then(function(response) {
this.token = response.data.token;
//if login token works then get records
getRecords();
})
.catch(function(xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
});
}
You can use 'crossDomain': true at your header of axios post, this is due to cors error. Your browser is making a Preflight Request, which uses the OPTIONS HTTP method. This is to check whether the server will allow the POST request – the 405 status code is sent in the response to the OPTIONS request, not your POST request
In this case, the following is causing the request to be preflighted:
if the Content-Type header has a value other than the following:
application/x-www-form-urlencoded
multipart/form-data
text/plain
The value for the Content-Type header is set to application/json;charset=utf-8 by axios. Using text/plain;charset=utf-8 or text/plain fixes the problem: You may try using like below.
source: App Script sends 405 response when trying to send a POST request
axios({
method: 'post',
headers: {
'crossDomain': true,
//'Content-Type': 'application/json',
'Content-Type': 'text/plain;charset=utf-8',
},
url: apiPostUrl,
data: {
user: "webuser",
password: "m0nk3yb#rz",
layout: "Main Menu"
},
})
.then(function(response) {
this.token = response.data.token;
//if login token works then get records
getRecords();
})
.catch(function(xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
});
I am trying to send a get request with auth headers to api from Vue using axios.
When I try to send it, it gives me a Network Error with no info about it. I have also check network tab and the request is not sending at all.
Before I checked the url using postman and https://www.hurl.it/ and it worked as expected.
Also, I have sent a request to this api using axios to get a token.
Thank you.
const token = "token";
let options = {
method: 'GET',
url: 'http://smev.test-it-studio.ru/api/analytics/PortfolioStructure',
headers: {
'Authorization': `Bearer ${token}`
},
};
axios(options).then((data) => {
console.log(data);
}).catch((error) => {
console.log(error.config);
});
EDIT: Here is the error I get:
Error
columnNumber: 15
config: {…}
adapter: function xhrAdapter()
baseURL: "http://smev.test-it-studio.ru"
data: undefined
headers: Object { Accept: "application/json", Authorization: "Bearer token"}
maxContentLength: -1
method: "GET"
timeout: 0
transformRequest: Object [ transformRequest() ]
transformResponse: Object [ transformResponse() ]
url: "http://smev.test-it-studio.ru/api/analytics/PortfolioStructure"
validateStatus: function validateStatus()
xsrfCookieName: "XSRF-TOKEN"
xsrfHeaderName: "X-XSRF-TOKEN"
__proto__: Object { … }
fileName: "http://uralsib-lk.dev/dist/build.js"
lineNumber: 19074
message: "Network Error"
response: undefined
stack: "createError#http://uralsib-lk.dev/dist/build.js:19074:15\nhandleError#http://uralsib-lk.dev/dist/build.js:18962:14\n"
__proto__: Object { … }
build.js:18589:24
With the help from Soleno, I found out that it was AdBlock what was blocking the request.
I had this problem in rails. It was cors as mentioned above.
The rails server won't show logs so it looks like axios isn't sending the request at all.
Thankfully it's an easy fix.
For rails add this to your gemfile:
gem 'rack-cors'
Then add this to config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0,Rack::Cors do
allow do
origins 'localhost:8080'
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
Note: Update orgins to the origin of your front end app.
I got Watson Speech-to-Text working on the web. I am now trying to do it on react native but am getting errors on the file upload part.
I am using the HTTPS Watson API. I need to set the Content-Type otherwise Watson returns a error response. However in react-native, for the file upload to work, we seem to need to set 'Content-Type' to 'multipart/form-data'. Is there anyway to upload a file in react-native while setting Content-Type to 'audio/aac'?
The error Watson API gives me if I set 'Content-Type': 'multipart/form-data' is:
{
type: "default",
status: 400,
ok: false,
statusText: undefined,
headers: Object,
url: "https://stream.watsonplatform.net/speech-to-text/api/v1/recognize?continuous=true",
_bodyInit: Blob,
_bodyBlob: Blob
}
The response body is:
{
"code_description": "Bad Request",
"code": 400,
"error": "No JSON object could be decoded"
}
Here is my code (full code is here - gist.github.com ):
const ext = 'aac';
const file_path = '/storage/emulated/0/Music/enter-the-book.aac';
data.append('file', {
uri: `file://${file_path}`,
name: `recording.${ext}`,
type: `audio/${ext}`
}, `recording.${ext}`);
const response = await fetch('https://stream.watsonplatform.net/speech-to-text/api/v1/recognize?continuous=true', {
method: 'POST',
headers: {
// 'Content-Type': `audio/${ext}`,
'Content-Type': 'multipart/form-data',
'X-Watson-Authorization-Token': token
},
body: data
});
console.log('watson-stt::getResults - response:', response);
if (response.status !== 200) {
const error = await response.text();
throw new Error(`Got bad response "status" (${response.status}) from Watson Speach to Text server, error: "${error}"`);
}
Here is a screenshot of the error I get when I set 'Content-Type': 'audio/aac':
Thanks so much to DanielBolanos and NikolayShmyrev this is the solution I used:
This code is for iOS so I recorded the audio as blah.ulaw BUT the part_content_type is aduio/mulaw;rate=22050 this is very important to use mulaw even though file ext is ulaw. An interesting note: I couldn't play the blah.ulaw file on my macOS desktop.
Also note that you MUST NOT set Content-Type to multipart/form-data this will destroy the boundary.
Also Bluemix requires rate in the part_content_type for mulaw
const body = new FormData();
let metadata = {
part_content_type: 'audio/mulaw;rate=22050' // and notice "mulaw" here, "ulaw" DOES NOT work here
};
body.append('metadata', JSON.stringify(metadata));
body.append('upload', {
uri: `file://${file_path}`,
name: `recording.ulaw`, // notice the use of "ulaw" here
type: `audio/ulaw` // and here it is also "ulaw"
});
const response = await fetch('https://stream.watsonplatform.net/speech-to-text/api/v1/recognize?continuous=true', {
method: 'POST',
headers: {
// 'Content-Type': 'multipart/form-data' // DO NOT SET THIS!! It destroys the boundary and messes up the request
'Authorization': `Basic ${btoa(`${USERNAME}:${PASSWORD}`)}`
},
body
});
According to the documentation for multipart requests the request should be:
curl -X POST -u "{username}":"{password}"
--header "Transfer-Encoding: chunked"
--form metadata="{
\"part_content_type\":\"audio/flac\",
\"timestamps\":true,
\"continuous\":true}"
--form upload="#audio-file1.flac"
"https://stream.watsonplatform.net/speech-to-text/api/v1/recognize"
So the content-type should be multipart/form-data, you can specify aac as "part_content_type": "audio/aac".
The big problem you have is that audio/aac is not in supported formats. You might probably need another codec.