web-dev-qa-db-fra.com

Composer plusieurs parties / données de formulaire avec un type de contenu différent sur chaque partie avec Javascript (ou angulaire)

Mauvaise question posée, voir ma mise à jour ci-dessous

J'ai besoin d'intégrer mon projet AngularJS avec une API RESTful existante. Ces API consomment POST demande qui upload a file, et soumettre également les données du formulaire dans une demande. Malheureusement, l'une des entrées du formulaire doit être dans Content-Type: Application/json.

Après une recherche sur le Web, je ne pouvais que POST avec Content-Type: multipart/form-data dans lequel chacune des parties n'a pas de MIME spécifique. Comment puis-je composer mon multipart/form-data avec un MIME différent pour chaque partie en Javascript?

POST /api/v1/inventory
Host: localhost:8000
Origin: http://localhost:9000
Content-Type: multipart/form-data; boundary=------border

------border
Content-Disposition: form-data; name="owner"

john doe
------border
Content-Disposition: form-data; name="image"; filename="mybook.png"
Content-Type: image/png


------border
Content-Disposition: form-data; name="items"
Content-Type: application/json

{"name": "Book", "quantity": "12"}
------border--

Références pertinentes:

  1. https://developer.mozilla.org/en-US/docs/Web/Guide/Using_FormData_Objects
  2. REST - HTTP Post Multipart avec JSON
  3. http://code.activestate.com/recipes/578846-composing-a-postable-http-request-with-multipartfo/
  4. application/x-www-form-urlencoded ou multipart/form-data?
  5. https://stackoverflow.com/a/9082243/764592

Mise à jour

Veuillez vous excuser d'avoir posé une mauvaise question. Le problème d'origine est que je peux voir le serveur appeler la logique quelque chose comme,

func POST(req):
     owner = req.owner // This is string
     image = req.image // This is file object
     itemQuantity = req.items.quantity // Items is an object with attribute quantity
     itemName = req.items.name // Items is an object with attribute name

J'ai également réussi à comprendre comment soumettre une telle demande de publication. Je posterai ma réponse ci-dessous.

Encore une fois désolé d'avoir posé une mauvaise question.

31
Yeo

Selon la documentation de FormData , vous pouvez ajouter un champ avec un type de contenu spécifique en utilisant le constructeur Blob :

var formData = new FormData();

formData.append('items', new Blob([JSON.stringify({
    name: "Book",
    quantity: "12"
})], {
    type: "application/json"
}));

Après une observation attentive, il s'avère qu'il enverra la pièce comme suit:

Content-Disposition: form-data; name="items"; filename="blob"
Content-Type: text/json

La seule alternative, à l'abri de la construction de la demande entière vous-même est de passer une valeur de chaîne:

formData.append('items', '{"name": "Book", "quantity": "12"}');

Malheureusement, cela ne définit pas le Content-Type entête.

56
Ja͢ck

Erreur # 1: Je suppose à tort que items doit être un json, afin que nous puissions appeler son attribut.

Solution: soumettre une demande en plusieurs parties contenant un fichier et un format de type objet est très simple.

form = new FormData();
form.append('items[name]', 'Book');
form.append('items[quantity]', 12);
form.append('image', imageFile);
form.append('owner', 'John Doe');

Ainsi, l'en-tête et le corps de la requête ressembleront à ceci

POST /api/v1/inventory
Host: localhost:8000
Origin: http://localhost:9000
Content-Type: multipart/form-data; boundary=------border

------border
Content-Disposition: form-data; name="owner"

john doe
------border
Content-Disposition: form-data; name="image"; filename="mybook.png"
Content-Type: image/png


------border
Content-Disposition: form-data; name="items[name]"

Book
------border
Content-Disposition: form-data; name="items[quantity]"

12
------border--
6
Yeo

Rien ne ferait fonctionner cela jusqu'à ce que je définisse le Content-Type en-tête non défini. Dans mon cas, je poste un fichier et quelques json.

public uploadFile(code: string, file):angular.IHttpPromise<any>{
    var data = `{"query":"mutation FIRMSCORECARD_CALCULATE($code:String!){ FirmScorecardMutation{ BatchCalculate(Code:$code) }}","variables":{"code":"${code}"},"operationName":"FIRMSCORECARD_CALCULATE"}`;
    var formData = new FormData();
    formData.append('operations', data);
    formData.append('file', file, file.name);

    let config = {
        headers: {
            'Accept': 'application/json',
            'Content-Type': undefined
        }
    };
    let response = this.$http.post(this.graphqlUrl, formData, config);
    return response;
}
0
N-ate