Can't get CORS to work on Cordova
rsmelo92 opened this issue · 13 comments
Hello, I'm trying to upload an image on cordova and I'm getting the error:
"XMLHttpRequest cannot load http://192.168.0.6:3000/gridfs/images/_resumable. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:12096' is therefore not allowed access. The response had HTTP status code 500."
Although I've setted the headers just like the documentation shows:
http: [
{
method: 'head',
path: '/id/:_id',
lookup: function (params, query) {
return {_id: new Mongo.ObjectID(params._id._str)};
},
handler: function (req, res, next) {
if (req.headers && req.headers.origin) {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin );
res.setHeader('Access-Control-Allow-Credentials', true);
}
next();
}
},
{
method: 'get',
path: '/id/:_id',
lookup: function (params, query) {
//console.log(Mongo);
//console.log("params._id._str:", params._id._str);
return {_id: new Mongo.ObjectID(params._id._str)};
},
handler: function (req, res, next) {
if (req.headers && req.headers.origin) {
res.setHeader('Access-Control-Allow-Origin', '*'); // For Cordova
res.setHeader('Access-Control-Allow-Credentials', true);
}
next();
}
},
{
method: 'put', // Enable a PUT endpoint
path: '/id/:_id',
lookup: function (params, query) { // uses express style url params
return {_id: new Mongo.ObjectID(params._id._str)};
},
handler: function (req, res, next) {
if (req.headers && req.headers.origin) {
res.setHeader('Access-Control-Allow-Origin', '*'); // For Cordova
res.setHeader('Access-Control-Allow-Credentials', true);
}
next();
}
},
{
method: 'post', // Enable a POST endpoint
path: '/id/:_id',
lookup: function (params, query) {
return {_id: new Mongo.ObjectID(params._id._str)};
},
handler: function (req, res, next) {
if (req.headers && req.headers.origin) {
res.setHeader('Access-Control-Allow-Origin', 'req.headers.origin'); // For Cordova
res.setHeader('Access-Control-Allow-Credentials', true);
}
next();
}
},
{
method: 'options', // Enable an OPTIONS endpoint (for CORS)
path: '/id/:_id',
lookup: function (params, query) { // uses express style url params
return {_id: new Mongo.ObjectID(params._id._str)};
},
handler: function (req, res, next) { // Custom express.js handler for OPTIONS
res.writeHead(200, {
'Content-Type': 'text/plain',
'Access-Control-Allow-Origin': 'req.headers.origin', // For Cordova
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Headers': 'user-agent',
'Access-Control-Allow-Methods': 'PUT,POST, HEAD, GET'
});
res.end();
return;
}
}
],
And I've setted this in the mobile-configs.js
App.accessRule('blob:*'); App.accessRule('*');
I still cant get it to work, can someone help me?
Hi, I'm not a Cordova expert, but if you are using resumable, it has a different URI endpoint.
Instead of /id/:_id
It uses /_resumable
So you'll probably need to add an OPTIONS enpoint for that path as well.
Thank you for your fast answer and of course for this great package, but I'm still unable to fix this...
I've done what you suggested but my app is never setting the headers with this option setted:
`{
method: 'options',
path: '/_resumable',
handler: function (req, res, next) {
res.writeHead(200, {
'Content-Type': 'text/plain',
'Access-Control-Allow-Origin': 'req.headers.origin',
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Headers': 'user-agent',
'Access-Control-Allow-Methods': 'PUT,POST, HEAD, GET'
});
res.end();
return;
}
}`
EDIT:
now I can get to set the headers but I'm getting this error, and I cant find it anywhere:
'Error in Dicer, no file found in POST'
what does that means?
Dicer is the MIME-multipart parser that file-collection uses to handle POST requests from resumable.js on the server-side.
That error is emitted from:
meteor-file-collection/src/http_access_server.coffee
Lines 99 to 101 in b668f4a
This case indicates that a POST request is coming in, but there is no file data encoded in the request data. The POST is built-up on the client side by resumable.js, file-collection doesn't touch that, so I'm guessing that there's still something wrong with the Cordova HTTP configuration such that the request body isn't being transmitted properly.
I'm not a Cordova developer, so I don't know what tools you have to debug this, but you somehow need to be able to inspect the HTTP POST requests coming out of resumable.js on the client to see what they look like, and verify that they are being transmitted correctly.
Apparently my resumable here is making a GET not a POST, because all the console logs are coming from the get only... It never passes through the POST consoles log.
********GET********
I20170414-17:51:02.838(-3)? --->> params {}
I20170414-17:51:02.838(-3)? --->> query { resumableChunkNumber: '1',
I20170414-17:51:02.839(-3)? resumableChunkSize: '1048576',
I20170414-17:51:02.839(-3)? resumableCurrentChunkSize: '16117',
I20170414-17:51:02.839(-3)? resumableTotalSize: '16117',
I20170414-17:51:02.840(-3)? resumableType: 'image/jpeg',
I20170414-17:51:02.840(-3)? resumableIdentifier: '2519e10fd606753910f409c1',
I20170414-17:51:02.840(-3)? resumableFilename: '1492203042655-cropped.jpg',
I20170414-17:51:02.840(-3)? resumableRelativePath: '1492203042655-cropped.jpg',
I20170414-17:51:02.840(-3)? resumableTotalChunks: '1' }
it goes through HEAD, then GET, then OPTIONS, maybe I'm doing something wrong? Should it pass through only POST instead of GET? How can I do it?
Hi, between the facts that I'm not a Cordova dev, I can't see your code, and I'm not the author of (nor do I support) the client-side of resumable.js, I don't think I can be of much more help to you.
From what I can tell, the problem here has something to do with the interaction between Cordova and resumable, neither of which I can support myself. I wish I had a better answer. You might try searching the issues in the resumable.js repo, others may have run into this and figured out a solution.
Alright, Thank you for your support and your time!
Sorry, just one more thing, is there any example of this package inserting image using server side nodejs stream?
Just the example code for the fc.importFile()
method.
https://github.com/vsivsi/meteor-file-collection#fcimportfilefilepath-file-callback
If you want to start with your own stream, rather than a file path, you can look to the source for this method here: https://github.com/vsivsi/meteor-file-collection/blob/master/src/gridFS_server.coffee#L342-L352
It's coffeescript, but a pretty simple function...
Thank you once again for your amazing help!
Hey it's me again. We were able to find a solution. It needed two important steps.
First the headers that worked for me were different from the readme:
http: [
{
method: 'get',
path: '/id/:_id',
lookup: function (params, query) {
return {_id: new Mongo.ObjectID(params._id._str)};
},
},
{
method: 'post', // Enable a POST endpoint
path: '/_resumable', // this will be at route "/gridfs/images/_resumable"
lookup: function (params, query) { // uses express style url params
return { }; // a query mapping url to images
},
handler: function (req, res, next) {
if (req.headers && req.headers.origin) {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin); // For Cordova
res.setHeader('Access-Control-Allow-Credentials', true);
}
next();
}
},
{
method: 'head', // Enable an HEAD endpoint (for CORS)
path: '/_resumable', // this will be at route "/gridfs/images/_resumable/"
lookup: function (params, query) { // uses express style url params
return { }; // a query mapping url to images
},
handler: function (req, res, next) { // Custom express.js handler for HEAD
if (req.headers && req.headers.origin) {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin); // For Cordova
res.setHeader('Access-Control-Allow-Credentials', true);
}
next();
}
},
{
method: 'options', // Enable an OPTIONS endpoint (for CORS)
path: '/_resumable', // this will be at route "/gridfs/images/_resumable/"
lookup: function (params, query) { // uses express style url params
return { }; // a query mapping url to images
},
handler: function (req, res, next) { // Custom express.js handler for OPTIONS
res.writeHead(200, {
'Content-Type': 'text/plain',
'Access-Control-Allow-Origin': req.headers.origin, // For Cordova
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Headers': 'x-auth-token, user-agent',
'Access-Control-Allow-Methods': 'GET, POST, HEAD, OPTIONS'
});
res.end();
return;
}
}
],
And the second step was that we were trying to upload a file type, and the code only worked when we converted it to a blob type. So if someone is struggling with the same problem try this: change the http headers and use a blob not a file!
Great news! Thanks for following-up to let me and future Cordova devs know what worked for you!
If you want to submit a PR to update/extend the docs for CORS/Cordova, I'd happily accept it!
Sorry for taking too long, of course, I will submit a PR to help with that!