Https POST de PHP para C #
-
10-07-2019 - |
Pergunta
Eu tenho que fazer um post para um terceiro https url para obter dados procesed e enviado de volta. E tudo o que tenho como um exemplo é o seguinte:
$signature= foo_string;
$data_to_post = json_dictionary;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $base_url);
curl_setopt($ch, CURLOPT_USERPWD, "$user:$password");
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER,array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_HTTPHEADER,array("JSON-Signature: $signature"));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_to_post);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
curl_close($ch);
Como trabalhamos com ASP .NET C # 2.0, eu tenho que esta porta, mas tenho sempre um erro não autenticated.
Aqui está o que eu estou fazendo:
HttpWebRequest q = (HttpWebRequest)WebRequest.Create(Host + ":" + Port);
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(new interhanse().AcceptAllCertifications);
q.Method = "POST";
q.Headers.Add("JSON-Signature:" + GetSignature(data));
q.ContentType = "application/json";
q.UseDefaultCredentials = false;
q.Credentials = new NetworkCredential(user,pwd, Host);
byte[] buffer = UTF8Encoding.UTF8.GetBytes(data);
q.ContentLength = data.Length;
Stream oStream = q.GetRequestStream();
StreamWriter oWriter = new StreamWriter(oStream);
oWriter.Write(buffer);
oWriter.Close();
HttpWebResponse reps = q.GetResponse() as HttpWebResponse;
Eu li todas as perguntas que eu possa encontrar sobre isso, mas eu não receber quaisquer melhorias. Agradecemos antecipadamente!
Solução
Bem, uma coisa que você está fazendo errado está assumindo que o comprimento em bytes é o mesmo que o comprimento em caracteres . Você deve usar buffer.Length para o comprimento de conteúdo. Você também está chamando StreamWriter.Write
com um array de bytes . Você não deveria fazer isso - você deve apenas usar o fluxo, como você já fez a codificação:
byte[] buffer = Encoding.UTF8.GetBytes(data);
q.ContentLength = buffer.Length;
using (Stream stream = q.GetRequestStream())
{
stream.Write(buffer, 0, buffer.Length);
}
Agora, isso não vai resolver o problema de autenticação. Você pode achar que apenas a criação resolve PreAuthenticate
que, embora:
q.PreAuthenticate = true;
Se isso não funcionar, eu sugiro que você executar WireShark e olhar para as diferenças entre o pedido através Curl e o pedido do .NET.
Outras dicas
Eu acho que você não deve fornecer o anfitrião na autenticação ...
q.Credentials = new NetworkCredential(user,pwd);
O que seria algo como:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Host + ":" + Port);
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(new interhanse().AcceptAllCertifications);
request.Method = "POST";
request.Headers.Add("JSON-Signature:" + GetSignature(data));
request.ContentType = "application/json";
request.UseDefaultCredentials = false;
request.Credentials = new NetworkCredential(user, pwd);
byte[] buffer = UTF8Encoding.UTF8.GetBytes(data);
request.ContentLength = buffer.Length;
using (Stream oStream = request.GetRequestStream()) {
oStream.Write(buffer, 0, buffer.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
// load data from response here
}
Além disso, você deve evitar atribuir o delegado validação ponto de serviço em cada solicitação, isso pode retardar os pedidos cada vez mais, porque a validação é realizada várias vezes, e é também uma espécie de fuga de memória.
curl_setopt($ch, CURLOPT_USERPWD, "$user:$password");
Aqui está como você acrescentar que CURLOPT_USERPWD em Asp.Net:
private async Task<string> Execute(string url, string query, string user, string pasword)
{
HttpClient httpClient = new HttpClient();
var baseUri = new Uri(url, UriKind.Absolute); // e.g. http://somedomain.com/endpoint
Uri request = new Uri(baseUri, query); // with query e.g. http://somedomain.com/endpoint?arg1=xyz&arg2=abc
// Add a new Request Message
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, request);
// add headers -> CURLOPT_USERPWD equivalent
var encodedStr = Convert.ToBase64String(Encoding.Default.GetBytes(string.Format("{0}:{1}", user, password)));
var authorizationKey = "Basic" + " " + encodedStr; // Note: Basic case sensitive
requestMessage.Headers.Add("Authorization", authorizationKey);
// if POST - do this instead
// content
//HttpContent content = new StringContent(jsonContent); // string jsonContent i.e. JsonConvert.SerializeObject(YourObject);
//requestMessage.Content = content;
//requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// execute
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
var responseString = await responseMessage.Content.ReadAsStringAsync(); // reads it as string;
// if json and you need to convert to an object do this
// var myresponse = JsonConvert.DeserializeObject<YourMappedObject>(responseString);
return responseString;
}