简体   繁体   中英

Angularjs file upload in put method not working

I have a simple todos application in which i am trying to upload a photo along with a single todo. Now i have created this factory function that takes care of the creation of the todo

  todosFactory.insertTodo = function(todo){
    return $http.post(baseUrl, todo, {
      headers: {
        'Content-Type' : undefined
      },
      transformRequest: function(data, headersGetter){
        var formData = new FormData();
        angular.forEach(data, function (value, key) {
            formData.append(key, value);
        });
        return formData;
      }
    });
  };

And the factory update method looks like this

  todosFactory.updateTodo = function(id, todo){
    return $http.put(baseUrl + '/' + id, todo, {
      headers: {
        'Content-Type' : undefined
      },
      transformRequest: function(data, headersGetter){
        var formData = new FormData();
        angular.forEach(data, function (value, key) {
            formData.append(key, value);
        });
        return formData;
      }
    });
  };

The insertTodo is working as expected but the updateTodo is not posting data to the server. I am using laravel for the API and the update API endpoint has this code

dd(Input::all(), Input::file('cover_photo'));

This shows that noting was posted in the request. And if i change the put to post in the updateTodo factory method it starts working. Am i missing some extra headers or something ?

Update

If i remove both the transformRequest and headers form the updateTodo method, the text data is successfully received on the server but the the file doesn't.
And if i just remove the headers nothing gets posted

Update

I am using the PHP server that comes with laravel using this command

php artisan serve

Update

Thanks to @Ricardo's answer i was able to get the submitted data using this code

router->put('/todos/{id}', function($id){
    $stream = file_get_contents("php://input");
    echo $stream;
    die();
});

I am getting the stream in this format

-----------------------------3643739756006088191021064137
Content-Disposition: form-data; name="id"

5
-----------------------------3643739756006088191021064137
Content-Disposition: form-data; name="name"

Image Todo
-----------------------------3643739756006088191021064137
Content-Disposition: form-data; name="complete"

0
-----------------------------3643739756006088191021064137
Content-Disposition: form-data; name="created_at"

2015-10-02 06:28:10
-----------------------------3643739756006088191021064137
Content-Disposition: form-data; name="updated_at"

2015-10-02 06:28:10
-----------------------------3643739756006088191021064137
Content-Disposition: form-data; name="cover_photo"; filename="Dragon-Falls-Venezuela-5.jpg"
Content-Type: image/jpeg

�����JFIF��H�H������Exif��MM�*�����i������������������z���,����UNICODE��C�R�E�A�T�O�R�:� 
�g�d�-�j�p�e�g� �v�1�.�0� �(�u�s�i�n�g� �I�J�G� �J�P�E�G� �v�6�2�)�,� �q�u�a�l�i�t�y� �=� �9�0�

Now i need to parse this raw format. I have found two php methods that other people have suggested http://php.net/manual/en/function.mb-parse-str.php and http://php.net/manual/en/function.parse-str.php but both of them are not working properly and do not give an array like $_GET or $_POST.

This piece from the PHP documentation discusses the PUT method and file uploads (multipart/form-data).

I can't quote any parts from it because I think everything is important. You should read it in detail but to summarize it's not possible without changes to your Apache configuration and creation of auxiliary scripts.

With Laravel you should use Form Method Spoofing (basically a variable called _method ) and keep on using POST. The _method will allow you to call Laravel's PUT action correctly.


Edit

AngularJS, by default, sends data in the JSON format which explains why you cannot access the data with the $_POST global. I have answered this in another question which explains what you have to do.

我认为您必须在服务器端序列化文件,如果您发送文件然后附加自定义标头并在服务器端适当处理该标头请求。

Create you formData upfront -> you don't need the transformer for that.
Add transformRequest : angular.identity to your HTTP headers. Your code should look similar to the snippet below:

$http.post('/api/endpoint', formData, {
  transformRequest : angular.identity,
  headers: {'Content-Type': undefined}
})
.success(function (data) {
  // do stuff with data
})
.error(function (error) {
  // recover from an error
});

Angular identity does nothing more than to spit back your form data: https://docs.angularjs.org/api/ng/function/angular.identity

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM