Fileupload to remote server


#1

I am trying from last two days, to upload a file to remote server.

I have built my own component which uses jquery $.ajax to post formdata, and also ember-ci-upload {ember-upload} plugin.

Sometimes I see the following error, and some time there is no error, But on the PHP side, there I never received the file.

XMLHttpRequest cannot load http://localhost:8000/api/demopages. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.

#2

this error happen because you not configure the Cors http on your backend. what kind of rest backend do you use?


#3

scandinave is correct, you need to enable cores on your backend server.

The reason why you never see the file is because the browser sends an OPTIONS request to your server to check CORs.

This should get you going with enabling: http://enable-cors.org/server.html


#4

I am having PHP backend, and I have set proper headers as far as I understand.

So far I have used Add/Edit/Delete all features. and also implemented ember-simple-auth for authentication. Everything else is working fine.

Here are my headers on the PHP side

header("Access-Control-Allow-Origin: http://localhost:4200");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
header('Access-Control-Max-Age: 1728000');
header("Access-Control-Allow-Credentials: true");
header("Content-Type: application/json; charset=utf-8");

#5

I have tried, with normal ajax page without ember, and my file did got uploaded to server. With the same headers on server side.

When I am sending file from normal ajax page following header is sent

Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryLIXMQovu3QtpydB1

But when sent from Ember it is

Content-Type:application/json;charset=utf-8

May be this is the issue? and how to resolve that?

I did some experiments and changed the content-type: multipart/form-data in ember component. Now it is giving me

XMLHttpRequest cannot load http://localhost:8000/api/demopages. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.

Which clearly is not the case as there are header present in the API, and which is working fine when sending a request outside the ember. So far as what I understand is something with Ember which is changing the outgoing request. Not sure.

Following request is sending proper data to server, but if I takeout form-urlencoded from header then server dont receive any thing

Ember.$.ajax({
  url: 'http://localhost:8000/demopage',
  data: {id: 1, title: 'Two'},
  type: 'POST',
  xhrFields: {
    withCredentials: true
  },
  beforeSend: function (xhr) {
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  },
});

So logically I shouldnt have to set that x-www-form-urlencoded content type.


#6

As I am testing more, I found that

  1. If I am using contentType: false ember/jquery should automatically change it properly, but in ember it is changing it to JSON which is wrong
  2. If i manually set the header to multipart then boundary is missing

Below is my current component, which is very straight forward

import Ember from 'ember';

export default Ember.TextField.extend({
  type: 'file',
  change: function (e) {
    var inputFiles = e.target.files;

    var inputFile = inputFiles[0];

    var fd = new FormData();
    fd.append('file', inputFile);

    Ember.$.ajax({
      url: 'http://localhost:8000/api/demopages',
      data: fd,
      cache: false,
      async: false,
      contentType: false,
      processData: false,
      type: 'POST',
      xhrFields: {
        withCredentials: true
      }
    });
  }
});

Here is my ember information

DEBUG: -------------------------------
DEBUG: Ember             : 1.13.10
DEBUG: Ember Data        : 1.13.12
DEBUG: jQuery            : 2.1.4
DEBUG: Ember Simple Auth : 0.8.0
DEBUG: -------------------------------

Ember-simple-auth with REST API and session cookie
#7

I just created a new project on other machine and tested the file upload with ember. It is working and files are being stored. So on my Mac, I have started a new ember app and slowly started to add each addon and started to configure. Checking file upload on each step.

Finally drilled down to my custom authorizer which I have used for simple auth, which is

import Ember from 'ember';
import Base from 'simple-auth/authorizers/base';

export default Base.extend({
  authorize: function(jqXHR, requestOptions) {
   // requestOptions.contentType = 'application/json;charset=utf-8';   <--- this line is creating the issue 
    requestOptions.crossDomain = true;
    requestOptions.xhrFields = {
      withCredentials: true
    };

    var token = this.get('session.token');
    if (this.get('session.isAuthenticated') && !Ember.isEmpty(token)) {
      jqXHR.setRequestHeader('X-CSRF-Token', token);
    }
  }
});

Any suggestions on improving this code? I had got it from Ember-simple-auth with REST API and session cookie

If I comment the line then I can not login to simple auth.

  1. Comment the line
  2. Login unsuccessful
  3. Uncomment the line so authorizer can work,
  4. Login, successful
  5. go to upload page
  6. Try to upload file didnt got uploaded
  7. commented the line in authorizer and tried again. File is uploaded to server

Here is my finding. When I have commented the line, the login page send data as Content-Type:application/x-www-form-urlencoded; charset=UTF-8 and I am not logged in on the server. I get 401. But if I am logged in all the other communication to the server is still made via Content-Type:application/json; charset=utf-8 and the file upload page use Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryyFVyavl08YPMzfmb and file is received on the server.

So simple-auth’s custom authentorizer is overriding the file upload multipart/form-data as json and which is the problem


#8

Here is the solution which I have used

import Ember from 'ember';
import Base from 'simple-auth/authorizers/base';

export default Base.extend({
  authorize: function(jqXHR, requestOptions) {

    if (!(requestOptions.data instanceof FormData)){
      requestOptions.contentType = 'application/json;charset=utf-8';
    }
    
    requestOptions.crossDomain = true;
    requestOptions.xhrFields = {
      withCredentials: true
    };

    var token = this.get('session.token');
    if (this.get('session.isAuthenticated') && !Ember.isEmpty(token)) {
      jqXHR.setRequestHeader('X-CSRF-Token', token);
    }
  }
});

I simply have checked if there is data and it is FormData then dont use content-type and let browser decide