HTTP Post как IE6 с использованием C # - PullRequest
11 голосов
/ 04 января 2012

Мне нужно сделать HTTP POST с использованием C #. Он должен выполнять обратную передачу так же, как страница 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--

Думаю, у меня проблемы с пограничными персонажами. Я попытался установить границу в данных поста, и fiddler показывает нечто подобное, но я получаю страницу с ошибкой «Недопустимый вызов процедуры или аргумент». Content-disposition находится в теле, а не в заголовке, чтобы держать его в границах. Я не уверен, что это правильно. Правильно ли я устанавливаю границу? Может кто-нибудь дать несколько советов о том, как сделать HTTP POST в стиле IE6 с использованием C #? Спасибо

Мой код

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;

Выход Fiddler (необработанный)

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--

Ответы [ 3 ]

4 голосов
/ 15 января 2012

Я думаю, что у вас есть две потенциальные проблемы:

1) Отправляемый URL-адрес форматирует параметр b_CustomerId иначе, чем реализация IE6.Если на сайт, на который вы ориентируетесь, не ожидается значение в кодировке HTML, это может быть источником сообщения об ошибке.

Ваш запрос:

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

Запрос IE6:

Upload.asp?b_customerId=[O/M1234]

Чтобы решить эту проблему, вы можете создать новый URL-адрес из перегрузки конструктора класса Uri , который был помечен как устаревший, но все еще работает правильно.Эта перегрузка позволяет указать, что строка уже экранирована во втором параметре.

Чтобы использовать этот конструктор, измените эту строку:

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 + 
3 голосов
/ 09 января 2012

У меня есть в блоге о способе загрузки нескольких файлов с помощью 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);
}
0 голосов
/ 14 января 2012

Это не будет полным ответом, но вы можете посмотреть на использование сокета вместо WebRequest и выполнение HTTP-запроса самостоятельно. Кажется, что на вашем сервере многокомпонентный обработчик не соответствует и ожидает, что запрос будет таким же, как в IE6, поэтому эмуляция, что вы сами, будет лучшим подходом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...