如何使用 HttpWebRequest 模拟浏览器文件上传

Posted

技术标签:

【中文标题】如何使用 HttpWebRequest 模拟浏览器文件上传【英文标题】:How to simulate browser file upload with HttpWebRequest 【发布时间】:2011-02-17 06:33:56 【问题描述】:

伙计们,首先感谢您的贡献,我在这里找到了很好的回应。但是我遇到了一个我无法弄清楚的问题,如果有人可以提供任何帮助,将不胜感激。

我正在用 C# 开发这个应用程序,它可以将图像从计算机上传到用户照片博客。为此,我使用pixelpost 主要用 php 编写的照片博客平台。

我在此处和其他网页上进行了搜索,但那里提供的示例对我不起作用。 这是我在示例中使用的内容:(Upload files with HTTPWebrequest (multipart/form-data)) 和 (http://bytes.com/topic/c-sharp/answers/268661-how-upload-file-via-c-code) 一旦准备就绪,我将在互联网上免费提供它,并且可能还会创建它的 Windows 移动版本,因为我是 pixelpost 的粉丝。

这是我使用的代码:

        string formUrl = "http://localhost/pixelpost/admin/index.php?x=login";
        string formParams = string.Format("user=0&password=1", "user-String", "password-String");
        string cookieHeader;
        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(formUrl);
        req.ContentType = "application/x-www-form-urlencoded";
        req.Method = "POST";
        req.AllowAutoRedirect = false;
        byte[] bytes = Encoding.ASCII.GetBytes(formParams);
        req.ContentLength = bytes.Length;
        using (Stream os = req.GetRequestStream())
        
            os.Write(bytes, 0, bytes.Length);
        
        HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
        cookieHeader = resp.Headers["Set-Cookie"];

        string pageSource;
        using (StreamReader sr = new StreamReader(resp.GetResponseStream()))
        
            pageSource = sr.ReadToEnd();
            Console.WriteLine();
        

        string getUrl = "http://localhost/pixelpost/admin/index.php";
        HttpWebRequest getRequest = (HttpWebRequest)HttpWebRequest.Create(getUrl);
        getRequest.Headers.Add("Cookie", cookieHeader);
        HttpWebResponse getResponse = (HttpWebResponse)getRequest.GetResponse();
        using (StreamReader sr = new StreamReader(getResponse.GetResponseStream()))
        
            pageSource = sr.ReadToEnd();
        

        // end first part: login to admin panel

        long length = 0;
        string boundary = "----------------------------" +
        DateTime.Now.Ticks.ToString("x");

        HttpWebRequest httpWebRequest2 = (HttpWebRequest)WebRequest.Create("http://localhost/pixelpost/admin/index.php?x=save");
        httpWebRequest2.ContentType = "multipart/form-data; boundary=" + boundary;
        httpWebRequest2.Method = "POST";
        httpWebRequest2.AllowAutoRedirect = false; 
        httpWebRequest2.KeepAlive = false;
        httpWebRequest2.Credentials = System.Net.CredentialCache.DefaultCredentials;
        httpWebRequest2.Headers.Add("Cookie", cookieHeader);



        Stream memStream = new System.IO.MemoryStream();

        byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");


        string formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"0\";\r\n\r\n1";

        string formitem = string.Format(formdataTemplate, "headline", "image-name");
        byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
        memStream.Write(formitembytes, 0, formitembytes.Length);

        memStream.Write(boundarybytes, 0, boundarybytes.Length);


        string headerTemplate = "\r\nContent-Disposition: form-data; name=\"0\"; filename=\"1\"\r\nContent-Type: application/octet-stream\r\n\r\n";



        string header = string.Format(headerTemplate, "userfile", "path-to-the-local-file");

        byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);

        memStream.Write(headerbytes, 0, headerbytes.Length);


        FileStream fileStream = new FileStream("path-to-the-local-file", FileMode.Open, FileAccess.Read);
        byte[] buffer = new byte[1024];

        int bytesRead = 0;

        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
        
            memStream.Write(buffer, 0, bytesRead);

        

        memStream.Write(boundarybytes, 0, boundarybytes.Length);

        fileStream.Close();


        httpWebRequest2.ContentLength = memStream.Length;

        Stream requestStream = httpWebRequest2.GetRequestStream();

        memStream.Position = 0;
        byte[] tempBuffer = new byte[memStream.Length];
        memStream.Read(tempBuffer, 0, tempBuffer.Length);
        memStream.Close();
        requestStream.Write(tempBuffer, 0, tempBuffer.Length);
        requestStream.Close();


        WebResponse webResponse2 = httpWebRequest2.GetResponse();

        Stream stream2 = webResponse2.GetResponseStream();
        StreamReader reader2 = new StreamReader(stream2);


        Console.WriteLine(reader2.ReadToEnd());

        webResponse2.Close();
        httpWebRequest2 = null;
        webResponse2 = null;

这里还有 PHP: (http://dl.dropbox.com/u/3149888/index.php) 和 (http://dl.dropbox.com/u/3149888/new_image.php)

必填字段是 headlineuserfile 所以我不知道错误在哪里,因为发送的格式是正确的。我猜发送到表单的八位字节流有问题。 也许这是一个我无法追踪的愚蠢错误,无论如何,如果你能帮助我,那将意味着很多。

谢谢,

【问题讨论】:

登录成功了吗,你找回cookie了吗? 是的,登录一切正常。我取回 cookie,如果我在控制台中显示 pageSource 字符串,就在“//结束第一部分:登录到管理面板”之前,它包含管理面板的 html 代码。对于第二个请求,当我发送所有表单数据和文件八位字节流时​​,我能够返回“提交”页面的 HTML,只有标题设置为“图像名称”并且没有图像上传到博客。所以,基本上我无法上传图片。通常,如果出现问题,我应该会收到一条错误消息,而是获得带有标题集的 HTML。 您是否尝试过运行 fiddler 来比较从浏览器提交时的 HTTP 流量与您的代码生成的流量?我通常发现这有助于深入了解此类问题。 非常感谢马丁,提琴手做出了改变。这实际上是提琴手指出的流格式错误。我不得不承认我以前从未使用过它,所以谢谢你的推荐。我将在下面发布更改,也许其他人也有兴趣。祝你好运! 【参考方案1】:

因此,Martin 在这里帮助了我,我能够对上面的代码进行重要更改,以使其正常工作。 Content-Type 必须更改为 image/jpeg。我也使用 C# Image 类型来发送图像流。

还要注意 Stream 格式,因为它不必包含额外的空格或换行符。

这里是修改的部分:

        string formUrl = "http://localhost/pixelpost/admin/index.php?x=login"; 
        string formParams = string.Format("user=0&password=1", "username", "password");
        string cookieHeader;
        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(formUrl);
        req.ContentType = "application/x-www-form-urlencoded";
        req.Method = "POST";
        req.AllowAutoRedirect = false;
        byte[] bytes = Encoding.ASCII.GetBytes(formParams);
        req.ContentLength = bytes.Length;
        using (Stream os = req.GetRequestStream())
        
            os.Write(bytes, 0, bytes.Length);
        
        HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
        cookieHeader = resp.Headers["Set-Cookie"];

        string pageSource;
        using (StreamReader sr = new StreamReader(resp.GetResponseStream()))
        
            pageSource = sr.ReadToEnd();
        

        string getUrl = "http://localhost/pixelpost/admin/index.php";
        HttpWebRequest getRequest = (HttpWebRequest)HttpWebRequest.Create(getUrl);
        getRequest.Headers.Add("Cookie", cookieHeader);
        HttpWebResponse getResponse = (HttpWebResponse)getRequest.GetResponse();
        using (StreamReader sr = new StreamReader(getResponse.GetResponseStream()))
        
            pageSource = sr.ReadToEnd();
        


        long length = 0;
        string boundary = "----------------------------" +
        DateTime.Now.Ticks.ToString("x");

        HttpWebRequest httpWebRequest2 = (HttpWebRequest)WebRequest.Create("http://localhost/pixelpost/admin/index.php?x=save");
        httpWebRequest2.ContentType = "multipart/form-data; boundary=" + boundary;
        httpWebRequest2.Method = "POST";
        httpWebRequest2.AllowAutoRedirect = false;
        httpWebRequest2.KeepAlive = false;
        httpWebRequest2.Credentials = System.Net.CredentialCache.DefaultCredentials;
        httpWebRequest2.Headers.Add("Cookie", cookieHeader);

        Stream memStream = new System.IO.MemoryStream();

        byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary);


        string headerTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"0\"; filename=\"1\"\r\nContent-Type: image/jpeg\r\n\r\n";



        string header = string.Format(headerTemplate, "userfile", "Sunset.jpg");



        byte[] headerbytes = System.Text.Encoding.ASCII.GetBytes(header);

        memStream.Write(headerbytes, 0, headerbytes.Length);


        Image img = null;
        img = Image.FromFile("C:/Documents and Settings/Dorin Cucicov/My Documents/My Pictures/Sunset.jpg", true);
        img.Save(memStream, System.Drawing.Imaging.ImageFormat.Jpeg);


        memStream.Write(boundarybytes, 0, boundarybytes.Length);


        string formdataTemplate = "\r\nContent-Disposition: form-data; name=\"0\";\r\n\r\n1";

        string formitem = string.Format(formdataTemplate, "headline", "Sunset");
        byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
        memStream.Write(formitembytes, 0, formitembytes.Length);

        memStream.Write(boundarybytes, 0, boundarybytes.Length);


        httpWebRequest2.ContentLength = memStream.Length;

        Stream requestStream = httpWebRequest2.GetRequestStream();

        memStream.Position = 0;
        byte[] tempBuffer = new byte[memStream.Length];
        memStream.Read(tempBuffer, 0, tempBuffer.Length);
        memStream.Close();
        requestStream.Write(tempBuffer, 0, tempBuffer.Length);
        requestStream.Close();


        WebResponse webResponse2 = httpWebRequest2.GetResponse();

        Stream stream2 = webResponse2.GetResponseStream();
        StreamReader reader2 = new StreamReader(stream2);


        Console.WriteLine(reader2.ReadToEnd());

        webResponse2.Close();
        httpWebRequest2 = null;
        webResponse2 = null;

再次感谢大家的回答或阅读。

【讨论】:

以上是关于如何使用 HttpWebRequest 模拟浏览器文件上传的主要内容,如果未能解决你的问题,请参考以下文章

vb.net如何使用HttpWebRequest模拟登陆带验证码的网站

c# httpwebrequest 模拟登陆

HttpWebRequest 保存Cookies,模拟Session登录

如何使用 httpwebrequest 将图像从网站拉到本地文件

转asp.net(c#)使用HttpWebRequest附加携带请求参数以post方式模拟上传大文件(以图片为例)到Web服务器端

markdown 模拟HttpWebRequest