C# 使用HttpWebRequest使用多部分/表单数据发布数据/上载图像

C# 使用HttpWebRequest使用多部分/表单数据发布数据/上载图像,c#,httpwebrequest,http-post,C#,Httpwebrequest,Http Post,我正在尝试使用ImageShack API上传图像。要使用它,我应该使用多部分/表单数据发布图像。我做的就像 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&"; po

我正在尝试使用ImageShack API上传图像。要使用它,我应该使用
多部分/表单数据
发布图像。我做的就像

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>

我认为您没有正确构建请求主体。 首先,您需要在内容类型标题中包含零件边界(随机文本)。比如说,

内容类型:多部分/表单数据; 边界=----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之类的工具来了解这些请求是如何生成的。

这与多部分/表单数据完全不同

  • 字段之间没有边界(即使只有一个字段也需要)
  • 你为什么使用base-64编码
  • 没有显示图像的内容类型

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

    我最终通过以下代码获得了它

    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;
    

    而且一切正常

    我不确定我是否仍然遗漏了任何内容,但我的请求数据(如显示的完整代码)也显示在屏幕上。我还是会犯同样的错误是的VinayC向我强调了这一点。我编辑了代码,看起来像现在。生成的post数据看起来像。。。值之后不需要后续换行。base-64ing是API特有的要求吗?这是不寻常的,但我可以看到API会如何要求它。由于base-64ing不是多种格式的一部分,因此您发送的不是图像/gif,而是文本/plain。除此之外,只要换行符是CRLFs,它看起来就是正确的。我建议不要以------作为边界名称的结尾,因为这样更难检查最后一个名称是否相同,但要额外加一个------如何发送图像?在我看到base64在某处使用后,我使用了它。所以也许我正在做wrong@jiewmeng,如果您说内容类型为image/gif,则可以获取图像字节并将其直接写入响应流。若API要求它是base64编码的,那个么内容类型不能是image/gif,而是text/plain.hmm,我是否犯了其他错误?我尝试发布到PHP脚本(localhost),但似乎没有任何
    $\u POST或$\u文件
    数据。我看不到在哪里使用
    文件头,也看不到在哪里添加文件内容。你也可以添加它吗?requestWriter.Write(string.Format(fileHeaderFormat,“image”,myImage.FileName,myImage.ContentType));requestWriter.Flush();Write(myImageAsByteArray,0,(myImageAsByteArray.Length);因此您可以使用requestWriter向请求写入字符串,但只需写入字节[]直接@user2102611
    reqWriter
    reqStream
    ,在这种情况下。不错,但是
    fileHeaderFormat
    只有2个参数,而且有点简单-必须确保它们也有文件字节:
    byte[]docBytes;使用(FileStream fs=file.OpenRead(@“C:\myPic.jpg”){docBytes=new byte[fs.Length];使用(BinaryReader br=new BinaryReader(fs)){docBytes=br.ReadBytes((int)fs.Length);}}if(docBytes!=null)reqStream.Write(docBytes,0,docBytes.Length);
    var propFormat = "--" + boundary + newLine +
                        "Content-Disposition: form-data; name=\"{0}\"" + newLine + newLine + 
                        "{1}" + newLine;