【问题标题】:HTTP Post as IE6 using C#使用 C# 作为 IE6 的 HTTP 发布
【发布时间】:2012-01-16 04:45:26
【问题描述】:

我需要使用 C# 进行 HTTP POST。它需要以与 IE6 页面相同的方式进行回发。

从文档来看,回发应该是这样的

POST /.../Upload.asp?b_customerId=[O/M1234] HTTP/1.1
Content-length: 12345
Content-type: multipart/form-data; boundary=vxvxv
Host: www.foo.com
--vxvxv
Content-disposition: form-data; name=”File1”; filename=”noColonsSpacesOrAmpersandsInHere”
Content-type: text/xml
<?xml version=”1.0” encoding=”UTF-8”?>
...
<bat:Batch ...
.......
</bat:Batch>
--vxvxv--

我认为边界字符有问题。我尝试在发布数据中设置边界,提琴手显示类似的内容,但我得到一个页面,并显示错误“无效的过程调用或参数”。 Content-disposition 位于正文而不是标题中,以将其保持在边界内。我不确定这是对的。我是否以正确的方式设置边界? 谁能提供一些关于如何使用 C# 进行 IE6 样式 HTTP POST 的指导?谢谢

我的代码

data = "--vxvxv" + Environment.NewLine + 
    "Content-disposition: form-data; name=\"File1\";" + Environment.NewLine + 
    "filename=\"provideTest.xml\"" + Environment.NewLine + 
    "Content-type: text/xml" + Environment.NewLine + 
    @"<?xml version=""1.0"" encoding=""UTF-8""?>" + Environment.NewLine + 
    data + Environment.NewLine + 
    "--vxvxv--";

var encoding = ASCIIEncoding.UTF8;
HttpWebRequest request;
var postData = encoding.GetBytes(data);

request = (HttpWebRequest)WebRequest.Create(url);
request.ContentLength = postData.Length;
request.Method = "POST";
request.ContentType = "multipart/form-data; boundary=vxvxv";
request.Host = "www.foo.com";
request.ContentLength = postData.Length;

X509Certificate2Collection certCollect = new X509Certificate2Collection();
X509Certificate2 cert = new X509Certificate2(@"C:\a\cert.pfx", "password");

certCollect.Add(cert);
request.ClientCertificates = certCollect;

using (Stream writeStream = request.GetRequestStream()) {
    writeStream.Write(postData, 0, postData.Length); }

WebResponse webResponse = request.GetResponse();
string output = new StreamReader(webResponse.GetResponseStream()).ReadToEnd();

LogEntry.Write("Recieved : " + output);
return output;

提琴手输出(原始)

POST https://../Upload.asp?b_customerId=%5BO/M1234%5D HTTP/1.1
Content-Type: multipart/form-data; boundary=vxvxv
Host: www.foo.com
Content-Length: 5500
Expect: 100-continue
Connection: Keep-Alive

--vxvxv
Content-disposition: form-data; name="File1";
filename="provideTest.xml"
Content-type: text/xml
<?xml version="1.0" encoding="UTF-8"?>
...SNIP...
</bat:Batch>
--vxvxv--

【问题讨论】:

  • 首先想到的是你的文件名在一个不应该的新行上。不知道这是否会导致提到的错误,但至少它可能会让事情变得很混乱。
  • 很确定这会使它无效。
  • 用换行符试过了。结果相同
  • 您在@"&lt;?xml version=""1.0"" encoding=""UTF-8""?&gt;" + Environment.NewLine + data + 中使用了相同的变量,这是正确的还是这里只是一个错字

标签: c# internet-explorer


【解决方案1】:

我认为你有两个潜在的问题:

1) 您发送的 URL 对 b_CustomerId 参数的格式不同于 IE6 实现。如果您定位的网站不期望 HTML 编码的值,这很容易成为错误消息的来源。

您的要求:

Upload.asp?b_customerId=%5BO/M1234%5D

IE6 请求:

Upload.asp?b_customerId=[O/M1234]

为了解决这个问题,您可以从Uri class constructor 的重载中创建一个新的网址,该网址已被标记为过时,但仍然可以正常工作。这个重载允许你在第二个参数中指定字符串已经被转义。

为了使用这个构造函数,改变这一行:

request = (HttpWebRequest)WebRequest.Create(url);

到这里:

request = (HttpWebRequest)WebRequest.Create(new Uri(url, true));

2) Content-disposition 标签在您的请求中的格式与在 IE6 请求中的格式不同。

您的要求:

Content-disposition: form-data; name="File1";
filename="provideTest.xml"

IE6 请求:

Content-disposition: form-data; name=”File1”; filename=”noColonsSpacesOrAmpersandsInHere”

这可以通过改变这两行来解决:

"Content-disposition: form-data; name=\"File1\";" + Environment.NewLine + 
"filename=\"provideTest.xml\"" + Environment.NewLine + 

到:

"Content-disposition: form-data; name=\"File1\"; " + 
"filename=\"provideTest.xml\"" + Environment.NewLine + 

【讨论】:

  • 如何阻止 [O/M1234] 被编码?我找不到我正在使用的课程的方法
  • @TomSquires:我已经更新了答案,提供了有关如何执行此操作的更多详细信息(我确实通过 fiddler 验证它传递了未转义的字符串)。
  • 奇怪的是,尽管给出的输出与文档中引用的完全相同,但它给出了相同的错误。不过,达尔文的方法确实奏效了。 (尽管看起来不像文档)。感谢您的帮助。
【解决方案2】:

我有blogged 关于使用 WebClient 上传多个文件的方法以及发送参数的可能性。以下是相关代码:

public class UploadFile
{
    public UploadFile()
    {
        ContentType = "application/octet-stream";
    }
    public string Name { get; set; }
    public string Filename { get; set; }
    public string ContentType { get; set; }
    public Stream Stream { get; set; }
}

然后是执行上传的方法:

public byte[] UploadFiles(string address, IEnumerable<UploadFile> files, NameValueCollection values)
{
    var request = WebRequest.Create(address);
    request.Method = "POST";
    var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);
    request.ContentType = "multipart/form-data; boundary=" + boundary;
    boundary = "--" + boundary;

    using (var requestStream = request.GetRequestStream())
    {
        // Write the values
        foreach (string name in values.Keys)
        {
            var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
            requestStream.Write(buffer, 0, buffer.Length);
            buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"{1}{1}", name, Environment.NewLine));
            requestStream.Write(buffer, 0, buffer.Length);
            buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine);
            requestStream.Write(buffer, 0, buffer.Length);
        }

        // Write the files
        foreach (var file in files)
        {
            var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
            requestStream.Write(buffer, 0, buffer.Length);
            buffer = Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"{2}", file.Name, file.Filename, Environment.NewLine));
            requestStream.Write(buffer, 0, buffer.Length);
            buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", file.ContentType, Environment.NewLine));
            requestStream.Write(buffer, 0, buffer.Length);
            file.Stream.CopyTo(requestStream);
            buffer = Encoding.ASCII.GetBytes(Environment.NewLine);
            requestStream.Write(buffer, 0, buffer.Length);
        }

        var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + "--");
        requestStream.Write(boundaryBuffer, 0, boundaryBuffer.Length);
    }

    using (var response = request.GetResponse())
    using (var responseStream = response.GetResponseStream())
    using (var stream = new MemoryStream())
    {
        responseStream.CopyTo(stream);
        return stream.ToArray();
    }
}

可以这样使用:

using (var stream1 = File.Open("test.txt", FileMode.Open))
using (var stream2 = File.Open("test.xml", FileMode.Open))
using (var stream3 = File.Open("test.pdf", FileMode.Open))
{
    var files = new[] 
    {
        new UploadFile
        {
            Name = "file",
            Filename = "test.txt",
            ContentType = "text/plain",
            Stream = stream1
        },
        new UploadFile
        {
            Name = "file",
            Filename = "test.xml",
            ContentType = "text/xml",
            Stream = stream2
        },
        new UploadFile
        {
            Name = "file",
            Filename = "test.pdf",
            ContentType = "application/pdf",
            Stream = stream3
        }
    };

    var values = new NameValueCollection
    {
        { "key1", "value1" },
        { "key2", "value2" },
        { "key3", "value3" },
    };

    byte[] result = UploadFiles("http://localhost:1234/upload", files, values);
}

【讨论】:

  • 那行得通。给你赏金。对于加分,你能解释为什么你的有效而我的没有?我注意到您在我使用文本的地方使用了“应用程序/八位字节流”。您似乎也没有设置内容长度。
【解决方案3】:

这不是一个完整的答案,但您可以考虑使用套接字而不是 WebRequest 并自己执行 HTTP 请求。您服务器上的 multipart 处理程序似乎不符合要求,并希望请求与 IE6 发出的请求相同,因此最好自己模拟。

【讨论】:

    猜你喜欢
    • 2022-01-20
    • 2018-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 1970-01-01
    • 2012-02-01
    相关资源
    最近更新 更多