WebRequest: como encontrar um código postal usando uma feveira web contra este contentType = “Application/xhtml+xml, text/xml, text/html; charset = utf-8 ”?
-
12-09-2019 - |
Pergunta
Eu postei isso pela primeira vez: Httpwebrequest: Como encontrar um código postal no Canadá POST através de um WebRequest com X-WWW-Form-Form?.
Seguindo as sugestões de Anthonywjones, mudei meu código após as sugestões dele.
Em uma continuação do meu inquérito, notei com o tempo que o tipo de conteúdo do Canadá é mais provável "Application/xhtml+xml, text/xml, text/html; charset = utf-8".
Minhas perguntas são:
- Como fazemos o WebRequest contra um site do tipo conteúdo?
- Temos que continuar com o objeto NameValuECollection?
- De acordo com Scott Lance, que generosamente me forneceu informações preciosas dentro da minha pergunta anterior, o WebRequest devolverá o tipo de informação que qualquer que seja o tipo de conteúdo, estou perdendo alguma coisa aqui?
- Tenho que alterar meu código por causa da alteração do tipo conteúdo?
Aqui está o meu código para que possa ser mais fácil entender meu progresso.
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;
}
}
}
Esse código realmente retorna o código -fonte HTML do formulário que se deve preencher com as informações necessárias para processar com a pesquisa de código postal. O que eu desejo é obter o código -fonte HTML ou o que quer que seja com o código postal encontrado.
EDITAR: Aqui está a WebException que recebo agora: "Não é possível enviar um órgão de conteúdo com esse tipo de verbo". (Esta é uma tradução da exceção francesa "Impossible D'Essoyer Un Corps do ConteNu Avec CE Type de Verbe".
Aqui está o meu código:
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;
}
A linha que causa a exceção é apontada com "=>". Parece que não posso usar o Get como método, mas é isso que me foi dito para fazer ...
Alguma ideia do que estou perdendo aqui? Eu tento fazer o que Justin (veja a resposta) me recomendou.
Agradecemos antecipadamente por qualquer ajuda! :-)
Solução
Como uma introdução ao mundo da escravo da tela, você escolheu um estojo muito difícil! A página de pesquisa do Canada Post funciona como esta:
- A primeira página é um formulário que aceita os valores do endereço
- Esta página publica em um segundo URL.
- Esse segundo URL, por sua vez, redireciona (usando um redirecionamento HTTP 302) para uma terceira URL que realmente mostra a resposta HTML contendo o código postal.
Piorando a situação, a página na etapa nº 3 precisa conhecer o biscoito definido na etapa 1. Então você precisa usar o mesmo CookieContainer
para todos os três pedidos (embora possa ser suficiente enviar o mesmo CookieContainer
apenas #2 e #3).
Além disso, pode ser necessário enviar cabeçalhos HTTP adicionais nessas solicitações, como aceitar. Suspeito que onde você esteja tendo problemas é que o httpwebrequest por alças padrão redireciona de forma transparente para você- mas quando o redireciona transparentemente, pode não adicionar os cabeçalhos HTTP certos necessários para se passar por um navegador.
A solução é definir o HttpWebRequest
's AllowAutoRedirect
propriedade para false e lidar com o redirecionamento. Em outras palavras, uma vez que a primeira solicitação retorne um redirecionamento, você precisará retirar o URL no HttpWebResponse
's Location:
cabeçalho. Então você precisará criar um novo HttpWebRequest
(Desta vez, uma solicitação GET regular, não uma postagem) para esse URL. Lembre -se de enviar o mesmo biscoito! (a CookieContainer
aula torna isso muito fácil)
Você também pode precisar fazer uma solicitação adicional (nº 1 na minha lista acima) para configurar o cookie da sessão. Se eu fosse você, presumo que isso seja necessário, simplesmente para eliminá -lo como um problema, e tentar remover essa etapa mais tarde e ver se sua solução ainda funciona.
Você vai querer baixar e usar Fiddler (www.fiddlertool.com) para ajudá -lo com tudo isso. O Fiddler permite que você assista às solicitações HTTP passando pelo fio e permite que você (por meio do recurso Builder de solicitações) permite criar solicitações HTTP para que você possa ver quais cabeçalhos são realmente necessários.