2016-08-16 3 views
2

Je suis dans le besoin d'afficher la demande suivante:affichage `multipart/form-data` avec Flurl

POST http://target-host.com/some/endpoint HTTP/1.1 
Content-Type: multipart/form-data; boundary="2e3956ac-de47-4cad-90df-05199a7c1f53" 
Accept-Encoding: gzip, deflate 
Connection: Keep-Alive 
Content-Length: 6971 
Host: target-host.com 

--2e3956ac-de47-4cad-90df-05199a7c1f53 
Content-Disposition: form-data; name="some-label" 

value 
--2e3956ac-de47-4cad-90df-05199a7c1f53 
Content-Disposition: form-data; name="file"; filename="my-filename.txt" 

<file contents> 
--2e3956ac-de47-4cad-90df-05199a7c1f53-- 

Je peux le faire très facilement avec la bibliothèque Python requests comme suit:

import requests 

with open("some_file", "rb") as f: 
    byte_string = f.read() 

requests.post(
    "http://target-host.com/some/endpoint", 
    data={"some-label": "value"}, 
    files={"file": ("my-filename.txt", byte_string)}) 

Est-il possible de faire la même chose avec la bibliothèque Flurl.Http?

Mon problème avec la façon documented de le faire est qu'il insère l'en-tête Content-Type pour chaque paire clé-valeur et il insère l'en-tête filename*=utf-8'' pour les données du fichier. Le serveur que j'essaye de signaler la demande, cependant, ne soutient pas ceci. Notez également les guillemets autour des valeurs name et filename dans les en-têtes.

EDIT: Voici le code que je l'habitude de faire la demande de poste avec Flurl.Http:

using System.IO; 
using Flurl; 
using Flurl.Http; 

namespace ConsoleApplication 
{ 
    public class Program 
    { 
     public static void Main(string[] args) 
     { 
      var fs = File.OpenRead("some_file"); 

      var response = "http://target-host.com" 
       .AppendPathSegment("some/endpoint") 
       .PostMultipartAsync(mp => mp 
        .AddString("some-label", "value") 
        .AddFile("file", fs, "my-filename.txt") 
       ).Result; 
     } 
    } 
} 
+0

C'est très réglo question de programmation. Est-ce que quelqu'un qui a voté pour le fermer pourrait expliquer? –

+0

Êtes-vous en train de dire que l'inclusion de 'filename 'dans l'en-tête avec les données du fichier a effectivement causé l'échec de l'appel? –

Répondre

2

Selon le spec (en date du Juin 2011), l'envoi à la fois filename et filename* est recommandé pour une compatibilité maximale:

De nombreuses implémentations d'agent utilisateur antérieures à cette spécification ne comprennent pas le paramètre "filename *". Par conséquent, lorsque "filename" et "filename *" sont présents dans une seule valeur de champ d'en-tête, les destinataires DEVRAIENT choisir "filename *" et ignorer "filename". De cette façon, les expéditeurs peuvent éviter les agents utilisateurs spécifiques à un boîtier spécial en envoyant à la fois le paramètre expressif "filename *" et le paramètre "filename" comme fallback pour les destinataires hérités.

Si filename* est à l'origine fait l'appel à échouent, il y a un vrai problème avec le serveur en respectant la spécification HTTP. En outre, entourer name et filename entre guillemets est très non standard. Cela dit, les raccourcis de Flurl couvrent les 90% des cas, mais vous pouvez toujours utiliser les API HttpClient sous-jacentes pour couvrir des cas inhabituels comme celui-ci. Dans ce cas, je pense que vous avez besoin de construire manuellement le contenu afin que vous puissiez faire face à ces Content-Disposition têtes:

var mpc = new MultipartContent(); 
var sc = new StringContent("value"); 
sc.Headers.Add("Content-Disposition", "form-data; name=\"some-label\""); 
mpc.Add(sc); 
var fc = new StreamContent(fs); 
fc.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"my-filename.txt\""); 
mpc.Add(fc); 

Ensuite, vous pouvez l'utiliser avec Flurl comme ceci:

var response = await "http://target-host.com"....PostAsync(mpc);