Использование HttpWebRequest для POST-данных/загрузка изображения с использованием multipart/form-data
Я пытаюсь использовать ImageShack API для загрузки изображений. Чтобы использовать его, я должен POST
использовать изображение с помощью multipart/form-data
. Я сделал это как...
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;
но ImageShack жалуется, что
<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 присутствует, и я использую multipart/form-data
, что не так?
ОБНОВЛЕНИЕ:
Новый код http://pastebin.com/TN6e0CD8
Опубликовать данные http://pastebin.com/fYE9fsxs
ОБНОВЛЕНИЕ 2
я посмотрел на другой вопрос Многостраничные формы от клиента С#. изменил мой код с помощью границы, удалил заголовок expect 100, но я не могу заставить его работать...
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();
}
Ответы
Ответ 1
Я считаю, что вы не строите тело запроса правильно.
Во-первых, вам нужно включить границу раздела (случайный текст) в заголовок типа контента. Например,
Content-Type: multipart/form-data; граница = ---- WebKitFormBoundarySkAQdHysJKel8YBM
Теперь формат тела запроса будет выглядеть как
------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]
Я предлагаю вам использовать такой инструмент, как Fiddler, чтобы понять, как эти запросы создаются.
Ответ 2
Я, наконец, получил его со следующим кодом...
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();
}
Обратите внимание, что границы должны начинаться с --
{границы, объявленной в ContentType}, а конечная граница должна начинаться и заканчиваться на --
. в моем случае я изначально использовал
var propFormat = boundary + newLine +
"Content-Disposition: form-data; name=\"{0}\"" + newLine + newLine +
"{1}" + newLine;
замените его на
var propFormat = "--" + boundary + newLine +
"Content-Disposition: form-data; name=\"{0}\"" + newLine + newLine +
"{1}" + newLine;
и все работает
Ответ 3
Это не что иное, как multipart/form-datap >
- Нет границ между полями (необходимо даже с одним полем).
- Почему вы используете кодировку base-64?
- Нет никаких указаний на тип содержимого содержимого.
Взгляните на RFC 2388 на фактическую спецификацию формата. Также может быть полезно посмотреть захват Fiddler загрузки файла с веб-страницы.