Https POST de Php en C #
-
10-07-2019 - |
Question
Je dois publier un message sur une URL https tierce pour que les données soient traitées et renvoyées. Et tout ce que j'ai comme exemple, c'est ceci:
$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);
Comme nous travaillons avec ASP .NET C # 2.0, je dois porter ceci, mais je reçois toujours une erreur non identifiée.
Voici ce que je fais:
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;
J'ai lu toutes les questions SO que je peux trouver à ce sujet, mais je n'obtiens aucune amélioration. Merci d'avance!
La solution
Eh bien, vous vous trompez en supposant que la longueur en octets est identique à la longueur en caractères . Vous devez utiliser buffer.Length pour la longueur du contenu. Vous appelez également StreamWriter.Write
avec un tableau d'octets . Vous ne devriez pas faire cela - vous devriez simplement utiliser le flux, comme vous l'avez déjà fait avec l'encodage:
byte[] buffer = Encoding.UTF8.GetBytes(data);
q.ContentLength = buffer.Length;
using (Stream stream = q.GetRequestStream())
{
stream.Write(buffer, 0, buffer.Length);
}
Cela ne résoudra pas le problème de l'authentification. Vous constaterez peut-être que le simple fait de définir PreAuthenticate
résout ce problème:
q.PreAuthenticate = true;
Si cela ne fonctionne pas, je vous suggère d'exécuter WireShark et d'examiner les différences entre la demande via Curl et la demande de .NET.
Autres conseils
Je pense que vous ne devriez pas fournir l'hôte dans l'authentification ...
q.Credentials = new NetworkCredential(user,pwd);
Ce qui ressemblerait à quelque chose comme:
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
}
Évitez également d'attribuer le délégué délégué à la validation du point de service à chaque requête. Cela pourrait ralentir les requêtes de plus en plus, car la validation est effectuée à plusieurs reprises et constitue en quelque sorte une fuite de mémoire.
curl_setopt($ch, CURLOPT_USERPWD, "$user:$password");
Voici comment vous ajoutez ce CURLOPT_USERPWD dans 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;
}