2013-05-10 13 views
40

Ich habe die unten Anfrage in Python

import requests, json, io 

cookie = {} 
payload = {"Name":"abc"} 
url = "/test" 
file = "out/test.json" 

fi = {'file': ('file', open(file))} 
r = requests.post("http://192.168.1.1:8080" + url, data=payload, files=fi, cookies=cookie) 
print(r.text) 

, die eine Datei, und Formularfelder an das Backend senden. Wie kann ich das gleiche tun (Datei + Formularfelder senden) mit Angular $ http. Momentan mag ich das, bin mir aber nicht sicher, wie ich die Datei auch senden soll.

var payload = {"Name":"abc"}; 
$http.post('/test', payload) 
    .success(function (res) { 
    //success 
}); 
+0

http://www.angulartutorial.net/2015/03/file-upload-and-sending-data-to: - Wenn Sie base64 Version einer Datei haben kann es leicht zu Blob wie so geändert werden -backend.html – Prashobh

+2

Bitte überprüfen Sie http://StackOverflow.com/a/25264008/144665 und markieren Sie als beste Antwort. Ich habe es fast vermisst! – iambriansreed

Antwort

6

ich kürzlich eine Richtlinie, die native unterstützt Upload von mehreren Dateien geschrieben. Die Lösung, die ich erstellt habe, beruht auf einem Dienst, um die Lücke zu füllen, die Sie mit dem Dienst $ http identifiziert haben. Ich habe auch eine Direktive eingefügt, die eine einfache API für Ihr eckiges Modul zur Verfügung stellt, um die Dateien und Daten zu veröffentlichen.

Beispiel Nutzung:

<lvl-file-upload 
    auto-upload='false' 
    choose-file-button-text='Choose files' 
    upload-file-button-text='Upload files' 
    upload-url='http://localhost:3000/files' 
    max-files='10' 
    max-file-size-mb='5' 
    get-additional-data='getData(files)' 
    on-done='done(files, data)' 
    on-progress='progress(percentDone)' 
    on-error='error(files, type, msg)'/> 

Sie können die code on github finden, und die Dokumentation über my blog

Es ist bis zu Ihnen sein würde, die Dateien in Ihrem Web-Framework zu verarbeiten, aber die Lösung, die ich habe erstellt bietet die eckige Schnittstelle, um die Daten auf Ihren Server zu bekommen. Der Winkel Code, den Sie schreiben müssen, um die Upload-Ereignisse

angular 
    .module('app', ['lvl.directives.fileupload']) 
    .controller('ctl', ['$scope', function($scope) { 
     $scope.done = function(files,data} { /*do something when the upload completes*/ }; 
     $scope.progress = function(percentDone) { /*do something when progress is reported*/ }; 
     $scope.error = function(file, type, msg) { /*do something if an error occurs*/ }; 
     $scope.getAdditionalData = function() { /* return additional data to be posted to the server*/ }; 

    }); 
+4

Dies scheint verwandt zu sein und einige anständige Informationen, aber könntest du es vielleicht ein bisschen erklären und es insbesondere mit dem Code in Verbindung bringen, den bsr hat, und wie dein Problem gelöst wird? –

+0

Guter Punkt, Antwort aktualisiert. – Jason

+0

Ausgezeichnet; Sieht gut aus! –

2

Sie können auch mit HTML5 laden. Sie können diese AJAX uploader verwenden.

Die JS-Code ist im Grunde:

$scope.doPhotoUpload = function() { 
    // .. 
    var myUploader = new uploader(document.getElementById('file_upload_element_id'), options); 
    myUploader.send(); 
    // .. 
    } 

, die von einem HTML-Eingabeelement liest

<input id="file_upload_element_id" type="file" onchange="angular.element(this).scope().doPhotoUpload()"> 
116

Ich hatte ähnliches Problem zu reagieren, wenn hatte Datei hochladen und Benutzer-Token Informationen zur gleichen Zeit senden. transformRequest zusammen mit Bildung FormData half:

 $http({ 
      method: 'POST', 
      url: '/upload-file', 
      headers: { 
       'Content-Type': 'multipart/form-data' 
      }, 
      data: { 
       email: Utils.getUserInfo().email, 
       token: Utils.getUserInfo().token, 
       upload: $scope.file 
      }, 
      transformRequest: function (data, headersGetter) { 
       var formData = new FormData(); 
       angular.forEach(data, function (value, key) { 
        formData.append(key, value); 
       }); 

       var headers = headersGetter(); 
       delete headers['Content-Type']; 

       return formData; 
      } 
     }) 
     .success(function (data) { 

     }) 
     .error(function (data, status) { 

     }); 

Für Datei bekommen $scope.file ich benutzerdefinierte Richtlinie verwendet:

app.directive('file', function() { 
    return { 
     scope: { 
      file: '=' 
     }, 
     link: function (scope, el, attrs) { 
      el.bind('change', function (event) { 
       var file = event.target.files[0]; 
       scope.file = file ? file : undefined; 
       scope.$apply(); 
      }); 
     } 
    }; 
}); 

Html:

<input type="file" file="file" required /> 
+11

Das funktioniert super! Sollte die akzeptierte Antwort sein. – aliasav

+3

Ich stimme zu, dass dies die akzeptierte Antwort sein sollte, da es Ihnen erlaubt, mit Ihrer eigenen API zu arbeiten, wo Tokens notwendig sein könnten. – CarbonDry

+4

Funktioniert als Charme. Wie ich luv wenn nur Kopieren/Einfügen funktioniert. Mann, spart viel Zeit. –

13

Ich war nicht in der Lage zu bekommen Pavel Antwort arbeitet wie in, wenn Veröffentlichung in einer Web.Api-Anwendung.

Das Problem scheint mit dem Löschen der Header zu sein.

headersGetter(); 
delete headers['Content-Type']; 

Um den Browser, um sicherzustellen, wurde den Content-Type zusammen mit dem Grenzparameter auf Standard erlaubt, musste ich den Content-Type auf undefined gesetzt. Bei Verwendung von Pavels Beispiel wurde die Grenze nie gesetzt, was zu einer 400 HTTP-Ausnahme führte.

Der Schlüssel bestand darin, den Code zu entfernen, der die oben gezeigten Header löscht, und den Header-Inhaltstyp manuell auf null zu setzen. So kann der Browser die Eigenschaften festlegen.

headers: {'Content-Type': undefined} 

Hier ist ein vollständiges Beispiel.

$scope.Submit = form => { 
       $http({ 
        method: 'POST', 
        url: 'api/FileTest', 
        headers: {'Content-Type': undefined}, 
        data: { 
         FullName: $scope.FullName, 
         Email: $scope.Email, 
         File1: $scope.file 
        }, 
        transformRequest: function (data, headersGetter) { 
         var formData = new FormData(); 
         angular.forEach(data, function (value, key) { 
          formData.append(key, value); 
         }); 
         return formData; 
        } 
       }) 
       .success(function (data) { 

       }) 
       .error(function (data, status) { 

       }); 

       return false; 
      } 
+1

Vielen Dank! Das scheint für mich zu funktionieren. – darkdefender27

0

In meiner Lösung, habe ich

$scope.uploadVideo = function(){ 
    var uploadUrl = "/api/uploadEvent"; 


    //obj with data, that can be one input or form 
    file = $scope.video; 
    var fd = new FormData(); 


    //check file form on being 
    for (var obj in file) { 
     if (file[obj] || file[obj] == 0) { 
      fd.append(obj, file[obj]); 
     } 
    } 

    //open XHR request 
    var xhr = new XMLHttpRequest(); 


    // $apply to rendering progress bar for any chunking update 
    xhr.upload.onprogress = function(event) { 
     $scope.uploadStatus = { 
      loaded: event.loaded, 
      total: event.total 
     }; 
     $scope.$apply(); 
    }; 

    xhr.onload = xhr.onerror = function(e) { 
     if (this.status == 200 || this.status == 201) { 

      //sucess 

      $scope.uploadStatus = { 
       loaded: 0, 
       total: 0 
      }; 


      //this is for my solution 
      $scope.video = {}; 
      $scope.vm.model.push(JSON.parse(e.currentTarget.response)); 
      $scope.$apply(); 

     } else { 
      //on else status 
     } 
    }; 

    xhr.open("POST", uploadUrl, true); 

    //token for upload, thit for my solution 
    xhr.setRequestHeader("Authorization", "JWT " + window.localStorage.token); 


    //send 
    xhr.send(fd); 
}; 

}

1

hier meine Lösung ist:

// Controller 
 
$scope.uploadImg = function(files) { 
 
    $scope.data.avatar = files[0]; 
 
} 
 

 
$scope.update = function() { 
 
    var formData = new FormData(); 
 
    formData.append('desc', data.desc); 
 
    formData.append('avatar', data.avatar); 
 
    SomeService.upload(formData); 
 
} 
 

 

 
// Service 
 
upload: function(formData) { 
 
    var deferred = $q.defer(); 
 
    var url = "/upload" \t ; 
 
    
 
    var request = { 
 
    "url": url, 
 
    "method": "POST", 
 
    "data": formData, 
 
    "headers": { 
 
     'Content-Type' : undefined // important 
 
    } 
 
    }; 
 

 
    console.log(request); 
 

 
    $http(request).success(function(data){ 
 
    deferred.resolve(data); 
 
    }).error(function(error){ 
 
    deferred.reject(error); 
 
    }); 
 
    return deferred.promise; 
 
} 
 

 

 
// backend use express and multer 
 
// a part of the code 
 
var multer = require('multer'); 
 
var storage = multer.diskStorage({ 
 
    destination: function (req, file, cb) { 
 
    cb(null, '../public/img') 
 
    }, 
 
    filename: function (req, file, cb) { 
 
    cb(null, file.fieldname + '-' + Date.now() + '.jpg'); 
 
    } 
 
}) 
 

 
var upload = multer({ storage: storage }) 
 
app.post('/upload', upload.single('avatar'), function(req, res, next) { 
 
    // do something 
 
    console.log(req.body); 
 
    res.send(req.body); 
 
});
<div> 
 
    <input type="file" accept="image/*" onchange="angular.element(this).scope().uploadImg(this.files)"> 
 
    <textarea ng-model="data.desc" /> 
 
    <button type="button" ng-click="update()">Update</button> 
 
</div>

0

Plea Sehen Sie sich meine Implementierung an. Sie können die folgende Funktion in einem Dienst wickeln:

function(file, url) { 
    var fd = new FormData(); 

    fd.append('file', file); 

    return $http.post(url, fd, { 
    transformRequest: angular.identity, 
    headers: { 'Content-Type': undefined } 
    }); 
} 

Bitte beachten Sie, dass file Argument ein Blob ist.

fetch(base64).then(function(response) { 
    return response.blob(); 
}).then(console.info).catch(console.error);