web-dev-qa-db-fra.com

Utilisation de HttpWebRequest pour POST données/télécharger une image avec multipart/form-data

J'essaie d'utiliser l'API ImageShack pour télécharger des images. Pour l'utiliser, je suis censé POST l'image à l'aide de multipart/form-data. Je l'ai fait comme ...

var postData = "";
var req = HttpWebRequest.Create("http://www.imageshack.us/upload_api.php");
req.Method = "POST";
req.ContentType = "multipart/form-data";
postData += "key=my_key_here&";
postData += "type=base64&";

// get base64 data from image
byte[] bytes = File.ReadAllBytes(@"D:\tmp\WpfApplication1\WpfApplication1\Images\Icon128.gif");
string encoded = Convert.ToBase64String(bytes);
postData += "fileupload=" + encoded;

byte[] reqData = Encoding.UTF8.GetBytes(postData);
using (Stream dataStream = req.GetRequestStream())
{
    dataStream.Write(reqData, 0, reqData.Length);
}

var res = (HttpWebResponse)req.GetResponse();
var resStream = res.GetResponseStream();
var reader = new StreamReader(resStream);
string resString = reader.ReadToEnd();
txt1.Text = resString;

mais ImageShack se plaint que 

<links>
    <error id="parameter_missing">Sorry, but we've detected that unexpected data is received. Required parameter 'fileupload' is missing or your post is not multipart/form-data</error>
</links>

FileUpload est présent et j'utilise multipart/form-data. Qu'est-ce qui ne va pas?

UPDATE:  

Nouveau code http://Pastebin.com/TN6e0CD8

Publier des données http://Pastebin.com/fYE9fsxs

UPDATE 2

j'ai regardé l'autre question Formulaires multipart de C # client . modifié mon code avec une limite, supprimé l'en-tête 100 prévu mais je n'arrive pas à le faire fonctionner ... 

ServicePointManager.Expect100Continue = false;
var boundary = "-----------------------------28520690214962";
var newLine = Environment.NewLine;
var propFormat = boundary + newLine +
                    "Content-Disposition: form-data; name=\"{0}\"" + newLine + newLine + 
                    "{1}" + newLine + newLine;
var fileHeaderFormat = boundary + newLine +
                        "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" + newLine;

var req = (HttpWebRequest)HttpWebRequest.Create("http://jm/php/upload.php");
req.Method = WebRequestMethods.Http.Post;
req.ContentType = "multipart/form-data; boundary=" + boundary;

using (var reqStream = req.GetRequestStream()) {
    var reqWriter = new StreamWriter(reqStream);
    var tmp = string.Format(propFormat, "str1", "hello world");
    reqWriter.Write(tmp);
    tmp = string.Format(propFormat, "str2", "hello world 2");
    reqWriter.Write(tmp);
    reqWriter.Write(boundary + "--");
    reqWriter.Flush();
}
var res = req.GetResponse();
using (var resStream = res.GetResponseStream()) {
    var reader = new StreamReader(resStream);
    txt1.Text = reader.ReadToEnd();
}
14
Jiew Meng

Je pense que vous ne construisez pas correctement le corps de la demande. Tout d'abord, vous devez inclure la limite de la pièce (texte aléatoire) dans l'en-tête du type de contenu. Par exemple,

Type de contenu: multipart/form-data; Frontière = ---- WebKitFormBoundarySkAQdHysJKel8YBM

Maintenant le format du corps de la requête sera quelque chose comme 

------WebKitFormBoundarySkAQdHysJKel8YBM 
Content-Disposition: form-data;name="key"

KeyValueGoesHere
------WebKitFormBoundarySkAQdHysJKel8YBM 
Content-Disposition: form-data;name="param2"

ValueHere
------WebKitFormBoundarySkAQdHysJKel8YBM 
Content-Disposition: form-data;name="fileUpload"; filename="y1.jpg"
Content-Type: image/jpeg 

[image data goes here]

Je vous suggérerai d'utiliser un outil tel que Fiddler pour comprendre comment ces demandes sont construites.

11
VinayC

Je l'ai finalement obtenu avec le code suivant ... 

var boundary = "------------------------" + DateTime.Now.Ticks;
var newLine = Environment.NewLine;
var propFormat = "--" + boundary + newLine +
                    "Content-Disposition: form-data; name=\"{0}\"" + newLine + newLine + 
                    "{1}" + newLine;
var fileHeaderFormat = "--" + boundary + newLine +
                        "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" + newLine;

var req = (HttpWebRequest)HttpWebRequest.Create("http://jm/php/upload.php");
req.Method = WebRequestMethods.Http.Post;
req.ContentType = "multipart/form-data; boundary=" + boundary;

using (var reqStream = req.GetRequestStream()) {
    var reqWriter = new StreamWriter(reqStream);
    var tmp = string.Format(propFormat, "str1", "hello world");
    reqWriter.Write(tmp);
    tmp = string.Format(propFormat, "str2", "hello world 2");
    reqWriter.Write(tmp);
    reqWriter.Write("--" + boundary + "--");
    reqWriter.Flush();
}
var res = req.GetResponse();
using (var resStream = res.GetResponseStream()) {
    var reader = new StreamReader(resStream);
    txt1.Text = reader.ReadToEnd();
}

Les limites de notification doivent commencer par -- {limite déclarée dans ContentType} et la limite de fin doit commencer et se terminer par --. dans mon cas, j'ai utilisé à l'origine

var propFormat = boundary + newLine +
                    "Content-Disposition: form-data; name=\"{0}\"" + newLine + newLine + 
                    "{1}" + newLine;

le remplacer par 

var propFormat = "--" + boundary + newLine +
                    "Content-Disposition: form-data; name=\"{0}\"" + newLine + newLine + 
                    "{1}" + newLine;

et tout fonctionne

11
Jiew Meng

Ce n'est rien comme multipart/form-data

  1. Il n'y a pas de frontière entre les champs (nécessaire même avec un champ).
  2. Pourquoi codez-vous en base 64?
  3. Il n'y a aucune indication sur le type de contenu de l'image.

Jetez un coup d'œil à la RFC 2388 pour connaître les spécifications de format réelles. Il peut également être utile de regarder une capture Fiddler d’un fichier téléchargé depuis une page Web.

0
Jon Hanna