WebRequest: Как найти почтовый индекс, используя WebRequest для этого ContentType="application/xhtml+xml, text/xml, text/html; charset=utf-8"?

Я впервые опубликовал это: HttpWebRequest: Как найти почтовый индекс на канадской почте через WebRequest с приложением в форме x-www?,

Следуя советам AnthonyWJones, я изменил свой код, следуя его советам.

Продолжая свой запрос, я заметил, что со временем тип контента Канадской почты, скорее всего, будет "application / xhtml + xml, text / xml, text / html; charset = utf-8".

Мои вопросы:

  1. Как нам сделать веб-запрос на такой веб-сайт типа контента?
  2. Должны ли мы продолжать работать с объектом NameValueCollection?
  3. Согласно Скотту Лэнсу, который щедро предоставил мне ценную информацию в моем предыдущем вопросе, WebRequest должен вернуть тип информации, какой бы ни был тип контента, я что-то здесь упускаю?
  4. Нужно ли менять код из-за изменения типа контента?

Вот мой код, чтобы было легче понять мой прогресс.

internal class PostalServicesFactory {
/// <summary>
/// Initializes an instance of GI.BusinessSolutions.Services.PostalServices.Types.PostalServicesFactory class.
/// </summary>
internal PostalServicesFactory() {
}
/// <summary>
/// Finds a Canadian postal code for the provided Canadian address.
/// </summary>
/// <param name="address">The instance of GI.BusinessSolutions.Services.PostalServices.ICanadianCityAddress for which to find the postal code.</param>
/// <returns>The postal code found, otherwise null.</returns>
internal string FindPostalCode(ICanadianCityAddress address) {
    if (address == null)
        throw new InvalidOperationException("No valid address specified.");

    using (ServicesWebClient swc = new ServicesWebClient()) {
        var values = new System.Collections.Specialized.NameValueCollection();

        values.Add("streetNumber", address.StreetNumber.ToString());
        values.Add("numberSuffix", address.NumberSuffix);
        values.Add("suite", address.Suite);
        values.Add("streetName", address.StreetName);
        values.Add("streetDirection", address.StreetDirection);
        values.Add("city", address.City);
        values.Add("province", address.Province);

        byte[] resultData = swc.UploadValues(@"http://www.canadapost.ca/cpotools/apps/fpc/personal/findByCity", "POST", values);

        return Encoding.UTF8.GetString(resultData);
    }
}

private class ServicesWebClient : WebClient {
    public ServicesWebClient()
        : base() {
    }
    protected override WebRequest GetWebRequest(Uri address) {
        var request = (HttpWebRequest)base.GetWebRequest(address);
        request.CookieContainer = new CookieContainer();
        return request;
    }
}
}

Этот код фактически возвращает исходный код HTML формы, которую необходимо заполнить необходимой информацией, чтобы выполнить поиск по почтовому индексу. Я хочу получить исходный код HTML или что-то еще с найденным почтовым индексом.

РЕДАКТИРОВАТЬ: Вот WebException, которое я получаю сейчас: "Невозможно отправить тело контента с этим типом глагола". (Это перевод с французского исключения "Невозможное общение с другими людьми")

Вот мой код:

    internal string FindPostalCode(string url, ICanadianAddress address) {
    string htmlResult = null;

    using (var swc = new ServiceWebClient()) {
        var values = new System.Collections.Specialized.NameValueCollection();

        values.Add("streetNumber", address.StreetNumber.ToString());
        values.Add("numberSuffix", address.NumberSuffix);
        values.Add("suite", address.Suite);
        values.Add("streetName", address.StreetName);
        values.Add("streetDirection", address.StreetDirection);
        values.Add("city", address.City);
        values.Add("province", address.Province);

        swc.UploadValues(url, @"POST", values);
        string redirectUrl = swc.ResponseHeaders.GetValues(@"Location")[0];
        => swc.UploadValues(redirectUrl, @"GET", values);
    }

    return htmlResult;
}

Строка, которая вызывает исключение, указывается с "=>". Кажется, я не могу использовать GET в качестве метода, но это то, что мне сказали, чтобы я сделал...

Есть идеи, что мне здесь не хватает? Я пытаюсь сделать то, что Джастин (см. Ответ) рекомендовал мне сделать.

Заранее благодарю за любую помощь!:-)

1 ответ

Решение

В качестве введения в мир скрипа скриншотов, вы выбрали очень сложный случай! Страница просмотра поста в Канаде работает следующим образом:

  1. первая страница представляет собой форму, которая принимает значения адреса
  2. эта страница отправляет на второй URL.
  3. этот второй URL, в свою очередь, перенаправляет (используя перенаправление HTTP 302) на третий URL, который фактически показывает HTML-ответ, содержащий почтовый индекс.

Что еще хуже, страница на шаге 3 должна знать файл cookie, установленный на шаге 1. Так что вам нужно использовать то же самое CookieContainer для всех трех запросов (хотя может быть достаточно отправить один и тот же CookieContainer только № 2 и № 3).

Кроме того, вам может потребоваться отправить дополнительные HTTP-заголовки в этих запросах, например, Accept. Я подозреваю, что вы сталкиваетесь с проблемами в том, что HttpWebRequest по умолчанию обрабатывает перенаправление прозрачно для вас - но когда он прозрачно перенаправляет, он может не добавить правильные заголовки HTTP, необходимые для олицетворения браузера.

Решение состоит в том, чтобы установить HttpWebRequest "s AllowAutoRedirect свойство ложно, и обрабатывать перенаправление самостоятельно. Другими словами, как только первый запрос вернет перенаправление, вам нужно будет извлечь URL в HttpWebResponse "s Location: заголовок. Тогда вам нужно будет создать новый HttpWebRequest (на этот раз обычный запрос GET, а не POST) для этого URL. Помните, чтобы отправить тот же файл cookie! (CookieContainer класс делает это очень легко)

Вам также может потребоваться сделать дополнительный запрос (#1 в моем списке выше), чтобы настроить cookie сессии. Если бы я был вами, я бы предположил, что это необходимо, просто чтобы устранить это как проблему, и попробуйте удалить этот шаг позже и посмотреть, работает ли еще ваше решение.

Вы можете скачать и использовать Fiddler ( http://www.fiddlertool.com/), чтобы помочь вам со всем этим. Fiddler позволяет вам наблюдать за HTTP-запросами, передаваемыми по проводам, и позволяет (с помощью функции построителя запросов) создавать запросы HTTP, чтобы вы могли видеть, какие заголовки действительно требуются.

Другие вопросы по тегам