【问题标题】:Using HttpWebRequest to POST data/upload image using multipart/form-data使用 HttpWebRequest 使用 multipart/form-data 发布数据/上传图像
【发布时间】:2011-04-22 21:20:53
【问题描述】:

我正在尝试使用 ImageShack API 上传图片。要使用它,我应该使用multipart/form-dataPOST 图像。我是这样做的......

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

我看了另一个问题Multipart forms from C# client。用边界修改了我的代码,删除了 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();
}

【问题讨论】:

标签: c# httpwebrequest http-post


【解决方案1】:

我终于用下面的代码搞定了……

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();
}

注意边界必须以 -- {boundary declaration in 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;

一切正常

【讨论】:

  • 我看不到您在哪里使用fileHeaderFormat 或在哪里添加文件内容。你也可以添加它吗?
  • requestWriter.Write(string.Format(fileHeaderFormat, "image", myImage.FileName, myImage.ContentType)); requestWriter.Flush(); requestStream.Write(myImageAsByteArray, 0, (myImageAsByteArray.Length); 因此,您使用 requestWriter 将字符串写入请求,然后直接写入您的 byte[]。
  • @user2102611 reqWriterreqStream,在这种情况下。不错,但fileHeaderFormat 只有 2 个参数,而且有点简单 - 必须确保它们也有文件字节:byte[] docBytes; using (FileStream fs = File.OpenRead(@"C:\myPic.jpg") { docBytes = new byte[fs.Length]; using (BinaryReader br = new BinaryReader(fs)) { docBytes = br.ReadBytes((int)fs.Length); } } if (docBytes != null) reqStream.Write(docBytes, 0, docBytes.Length);
【解决方案2】:

我相信您没有正确构建请求正文。 首先,您需要在内容类型标题中包含部分边界(随机文本)。例如,

内容类型: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 之类的工具来了解这些请求是如何构建的。

【讨论】:

  • 我不确定我是否仍然错过了任何东西,但我的请求数据(如 @pastebin 上的完整代码也显示在 pastebin 上)。我仍然得到同样的错误
【解决方案3】:

这与 multipart/form-data 完全不同

  1. 字段之间没有界限(即使只有一个字段也需要)。
  2. 为什么要使用 base-64 编码?
  3. 没有指明图片的内容类型。

查看 RFC 2388 以了解实际的格式规范。查看从网页上传的文件的 Fiddler 抓取也很有用。

【讨论】:

  • 是的,VinayC 向我强调了这一点。我编辑了代码,现在看起来像@pastebin。并且生成的帖子数据看起来像...... @pastebin
  • 值之后不需要后续的换行符。 base-64 是 API 特有的要求吗?这很不寻常,但我可以看到 API 可能会要求它。由于 base-64ing 不是多格式格式的一部分,因此您发送的不是图像/gif,而是文本/纯文本。除此之外,只要换行符是 CRLF,它看起来是正确的。我建议不要以 ----- 结束边界名称,因为这样会更难检查最后一个名称是否相同,但要加上一个额外的 --
  • 如何发送图像?在看到它在某处使用后,我使用了 base64。所以也许我做错了
  • @jiewmeng,如果您说 content-type 是 image/gif 那么您可以获取图像字节并将它们直接写入响应流。如果 API 要求它采用 base64 编码,则内容类型不能是 image/gif,而是 text/plain。
  • 嗯,我是否犯了其他错误?我尝试发布到 PHP 脚本(本地主机),但我似乎没有任何 $_POST or $_FILE 数据
猜你喜欢
  • 1970-01-01
  • 2011-11-01
  • 2018-12-26
  • 1970-01-01
  • 1970-01-01
  • 2015-10-11
  • 1970-01-01
  • 2011-03-22
  • 2019-05-23
相关资源
最近更新 更多