Multipart/form-data samenstellen met een ander Content-Type op elk onderdeel met Javascript (of Angular)

Onjuiste vraag gesteld, zie mijn update hieronder

Ik moet mijn AngularJS-project integreren met een bestaande RESTful API. Deze API verbruikt POST-verzoeken die upload a fileen dienen ook de formuliergegevens in een verzoek in. Helaas moet een van de formulierinvoer in Content-Type: Application/jsonzijn.

Na zoeken op internet kon ik alleen POSTmet Content-Type: multipart/form-datawaarin geen van de onderdelen een specifieke MIME.
Hoe kan ik mijn multipart/form-datasamenstellen met een andere MIMEvoor elk onderdeel in 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--

Relevante referenties:

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

Bijwerken

Excuses voor het stellen van een verkeerde vraag. Het oorspronkelijke probleem is dat ik de server de logica kan zien roepen zoiets als,

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

Ik ben er ook in geslaagd om erachter te komen hoe ik zo’n postverzoek kan indienen. Ik zal mijn antwoord hieronder plaatsen.

Nogmaals sorry voor het stellen van een verkeerde vraag.


Antwoord 1, autoriteit 100%

Volgens de documentatie van FormData, kunt u een veld met een specifiek inhoudstype toevoegen met behulp van de Blob-constructor:

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

Na zorgvuldige observatie blijkt dat het het onderdeel als volgt zal verzenden:

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

Het enige alternatief, veilig om het hele verzoek zelf te bouwen, is om een ​​stringwaarde door te geven:

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

Hierdoor wordt helaas de Content-Typeheader niet ingesteld.


Antwoord 2, autoriteit 8%

Fout #1: Ik neem ten onrechte aan dat de itemseen json moeten zijn, zodat we het attribuut kunnen noemen.

Oplossing: het is heel eenvoudig om een ​​meerdelige aanvraag in te dienen die een bestand en een objectachtig formaat bevat.

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

Dus dus zullen de header en body van het verzoek er ongeveer zo uitzien

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--

Antwoord 3, autoriteit 3%

Niets zou dit laten werken, totdat ik de Content-Typeheader op undefined zette. In mijn geval plaats ik een bestand en wat 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;
}

Other episodes