J'utilise httpClientFactory
pour demander une API Wechat Pay, mais l'API Wechat Pay a besoin d'un certificat. Comment puis-je configurer httpClientFactory
pour utiliser le certificat?
3 Réponses :
Tout d'abord, vous devez vous enregistrer HttpClient
:
public class PayClient { private readonly ICurrentUserProvider _currentUserProvider; public PayClient(ICurrentUserProvider _currentUserProvider) { _currentUserProvider = currentUserProvider; } private HttpClient CreateHttpClient() { var currentUser = _currentUserProvider.CurrentUser; var filename = currentUser.CertificateFilename; var password = currentUser.CertificatePassword; var handler = new HttpClientHandler(); var certificate = new X509Certificate2(filename, password); handler.ClientCertificateOptions = ClientCertificateOptions.Manual; handler.ClientCertificates.Add(certificat); return new HttpClient(handler); } public async Task SomePayMethodAsync() { using (httpClient = CreateHttpClient()) { // use httpClient } } }
Dans l'exemple, le fichier foo.pfx contient un certificat avec le mot de passe 123 .
** signé * est le nom de HttpClient
.
Deuxièmement, vous appellerez IHttpClientFactory.CreateClient
pour créer le HttpClient code > instance.
public class PayClient { private readonly IHttpClientFactory _httpClientFactory; public PayClient(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public async Task SomePayMethodAsync() { using (httpClient = _httpClientFactory.CreateClient("signed")) { // use httpClient } } }
Vous devez utiliser le même nom signé que le paramètre de CreateClient
.
MISE À JOUR PLUS TARD
Si vous écrivez SAAS avec de nombreux certificats, vous pouvez créer et configurer manuellement un HttpClient
chaque fois que vous en avez besoin. C'est le moyen le plus simple.
services.AddHttpClient("signed") .ConfigurePrimaryMessageHandler(() => { var handler = new HttpClientHandler(); var certificate = new X509Certificate2(filename: "foo.pfx", password: "123"); handler.ClientCertificateOptions = ClientCertificateOptions.Manual; handler.ClientCertificates.Add(certificat); });
Mais, comment configurer différents cert avec la même URL d'API. parce que j'ai beaucoup de comptes différents et de certificats différents pour demander une même URL d'API.
@ junlei.lv Vous pouvez enregistrer quelques clients avec des noms différents. Chaque classe comme PayClient
peut créer son propre HttpClient
. Habituellement, vous avez un certificat unique pour certains services distants, cette décision devrait donc fonctionner.
Merci beaucoup.Mais cette méthode ne peut pas résoudre ma question.parce que mon logiciel est une plate-forme saas.nous avons beaucoup de clients.Chaque client a un certificat différent.Mais l'adresse de l'api payante est la même.So.enregistrez quelques clients avec des noms différents. pas très bon.
avez-vous un autre moyen?
@ junlei.lv J'ai mis à jour ma réponse avec la solution alternative. Peut-être que cela vous convient mieux.
en fait, j'utilise cette méthode maintenant. mais cette méthode créera de nombreux tcp time_wait
pouvons-nous parler de cette question par e-mail?
@ junlei.lv Si vous souhaitez optimiser le code, vous pouvez mettre en cache les instances HttpClientHandler
. En tant que base, vous pouvez obtenir l'implémentation de la classe DefaultHttpClientFactory
ici .
L'approche de «mise à jour ultérieure» ne conduira-t-elle pas à l'épuisement des ports?
Si vous regardez la fabrique par défaut retournée dans DI, elle hérite de deux interfaces, et lors de l'injection vous avez choisi de n'en utiliser qu'une:
classe interne DefaultHttpClientFactory: IHttpClientFactory, IHttpMessageHandlerFactory
p >
Sachant cela, vous pouvez prendre une solution de contournement sournoise:
_handlerFactory = _clientFactory as IHttpMessageHandlerFactory;
Maintenant, si vous regardez l'usine de gestionnaires, il a une méthode CreateHandler
avec le même argument de chaîne que la méthode CreateClient
. En fait, si vous regardez l'implémentation de CreateClient
, vous pouvez voir qu'il utilise cette méthode qui met ensuite en cache le gestionnaire.
Alors oubliez Startup: Cast votre usine client en usine de gestionnaire, créez un gestionnaire pour votre utilisateur spécifique, vérifiez toutes les propriétés du gestionnaire (comme le certificat ou devez-vous l'ajouter puisqu'il s'agit d'une nouvelle instance), puis appelez CreateClient
comme d'habitude. p >
Modifier: Au démarrage, vous devrez peut-être encore ajouter ConfigurePrimaryHttpMessageHandler pour créer réellement un HttpClientHandler, vous devrez donc peut-être faire une consession en n'enregistrant qu'un seul nommé HttpClient et en échangeant simplement le certificat. Cela vous donne quand même les avantages d'avoir l'usine.
Edit 2: sachez que le gestionnaire est emballé un tas de fois dans les décorateurs, vous devez donc creuser profondément. L'astuce que j'utilise est:
var handler = _handlerFactory.CreateHandler("customer"); while (handler as DelegatingHandler != null) { handler = (handler as DelegatingHandler).InnerHandler; } var clientHandler = handler as HttpClientHandler;
C'est bien! J'utilise.NET Core 3.1 main ayant des problèmes et je pense que cela le résout. J'essaye d'échanger le certificat par demande (semblable à l'OP). Pouvez-vous nous expliquer à quoi ressemblerait la startup? Cela m'aiderait tellement!
J'ai ajouté des services.AddHttpClient (); mais quand j'ai utilisé le DI IHttpMEssageHandlerFactory, il est nul. Un conseil s'il vous plait? Merci
services.AddHttpClient("configured-disable-automatic-cookies") .ConfigurePrimaryHttpMessageHandler(() => { return new SocketsHttpHandler() { UseCookies = false, }; });