TL;DR — Une requête HTTP lancée depuis VBA vous rend exactement deux choses : un code de statut et un bloc d'octets. Elle ne vous dit pas si les données sont fraîches, quel encodage de texte utilisent ces octets, ni même si la requête a atteint le serveur à temps. Tout cela, c'est votre travail. Choisissez l'objet en fonction du réseau qu'il doit traverser (
MSXML2.XMLHTTPutilise les paramètres et le cache du navigateur de l'utilisateur,ServerXMLHTTPetWinHttpRequestvous donnent des délais d'expiration et aucun cache), vérifiez le statut vous-même, car un 404 ou un 500 ne déclenche jamais d'erreur, et décodez les octets délibérément dès que le serveur envoie autre chose que de l'UTF-8.
Dim http As Object
Set http = CreateObject("MSXML2.ServerXMLHTTP.6.0")
http.setTimeouts 5000, 5000, 10000, 30000
http.Open "GET", "https://api.example.com/rates?base=EUR", False
http.send
If http.Status = 200 Then Debug.Print http.responseText
Voici le premier article d'une série consacrée à faire entrer des données du web dans Excel : ici la requête elle-même, puis VBA JSON pour transformer la réponse en structure, et web scraping en VBA pour les pages qui n'ont jamais été conçues pour être lues par du code. L'idée de la série : une requête web vous remet du texte, pas des données. Entre le serveur et vos cellules se trouvent trois traductions qui vous appartiennent : des octets au texte, du texte à la structure, de la structure à la grille. Presque toutes les pannes se produisent à l'une de ces frontières, pas dans la requête.
Ce que vous allez apprendre
- Le modèle mental : un statut et quelques octets
- Trois objets, trois piles réseau
- Deux sortes d'échec : les erreurs qui se déclenchent et les statuts qui ne déclenchent rien
- Pourquoi un GET renvoie les données d'hier
- Les délais d'expiration, et pourquoi une requête peut figer Excel
- Accents illisibles : décoder les octets vous-même
- Envoyer un POST avec un corps JSON
- Chaînes de requête et clés d'API
Le modèle mental : un statut et quelques octets
Quand vous appelez http.send, VBA confie la requête à une bibliothèque réseau de Windows et attend. Ce qui
revient est maigre : un nombre (Status, par exemple 200 ou 404), quelques en-têtes, et le corps sous forme
d'octets. responseText n'est pas le corps ; c'est le corps déjà décodé en texte sur la foi d'une
supposition. responseBody, ce sont les octets bruts.
Gardez cette image en tête et les pannes étranges cessent de l'être. Des données périmées signifient qu'une couche entre vous et le serveur a répondu à sa place. Un texte illisible signifie que la supposition de décodage était fausse. Une macro qui « marchait hier » et qui se bloque aujourd'hui signifie que le réseau a ralenti et que rien n'a dit à la requête d'abandonner.
Trois objets, trois piles réseau
Les trois objets que l'on copie depuis les forums semblent interchangeables. Ils ne le sont pas : chacun repose sur une pile réseau Windows différente, et c'est la pile qui décide du comportement de la requête sur le poste de votre utilisateur.
| Objet | Pile réseau | Cache | Proxy et authentification | Délais d'expiration |
|---|---|---|---|---|
MSXML2.XMLHTTP.6.0 |
WinINet (la pile derrière les anciens paramètres du navigateur) | oui, les réponses GET peuvent être mises en cache | utilise automatiquement les paramètres Internet Windows de l'utilisateur | pas de méthode setTimeouts |
MSXML2.ServerXMLHTTP.6.0 |
WinHTTP | non | le paramètre proxy propre à WinHTTP, souvent vide ; setProxy pour en définir un |
setTimeouts |
WinHttp.WinHttpRequest.5.1 |
WinHTTP | non | comme ci-dessus ; SetProxy |
SetTimeouts, plus des options comme les versions de TLS |
Ce tableau explique le ticket de support le plus fréquent : « ça marche sur mon portable et ça échoue dans les
bureaux du client ». Les bureaux font passer le web par un proxy. XMLHTTP récupère ce proxy dans les
paramètres de l'utilisateur ; ServerXMLHTTP et WinHttpRequest non, si bien qu'ils ne peuvent pas se
connecter alors que le navigateur de la même machine fonctionne très bien. Indiquez-leur le proxy
explicitement :
http.setProxy 2, "proxy.company.local:8080" ' 2 = utiliser ce proxy
Les trois se créent avec CreateObject et ne demandent aucune référence, si bien que le même code tourne dans
Office 32 bits comme 64 bits. Voir VBA CreateObject pour la liaison tardive en
général.
Deux sortes d'échec : les erreurs qui se déclenchent et les statuts qui ne déclenchent rien
Une requête peut échouer à deux endroits, et VBA vous le signale par deux canaux différents.
Les échecs de transport déclenchent une erreur d'exécution. Pas de réseau, un nom de serveur qui ne se
résout pas, un délai dépassé, une négociation TLS qui échoue : send s'arrête sur une erreur d'exécution,
généralement un grand nombre négatif comme -2147012889 (le nom du serveur n'a pas pu être résolu) ou
-2147012894 (le délai de l'opération a expiré). Interceptez-les avec On Error.
Les échecs HTTP ne déclenchent rien du tout. Un 404, un 401 parce que la clé a expiré, un 500 parce que le
serveur est en panne : send se termine normalement, Status contient le code et responseText contient une
page d'erreur ou un JSON d'erreur. Un code qui saute la vérification du statut écrit sans broncher
« Unauthorized » ou une page de HTML dans votre feuille.
Chaque requête a donc besoin des deux vérifications. Regroupez-les dans une seule fonction et n'appelez send
nulle part ailleurs :
Function HttpGet(ByVal url As String) As String
Dim http As Object
Set http = CreateObject("MSXML2.ServerXMLHTTP.6.0")
http.setTimeouts 5000, 5000, 10000, 30000
http.Open "GET", url, False
http.setRequestHeader "Accept", "application/json"
http.send ' les erreurs de transport se declenchent ici
If http.Status < 200 Or http.Status >= 300 Then
Err.Raise vbObjectError + 513, "HttpGet", _
"HTTP " & http.Status & " " & http.statusText & " for " & url
End If
HttpGet = http.responseText
End Function
Désormais, les deux sortes d'échec arrivent sous forme d'erreur d'exécution avec un message lisible, et l'appelant les traite en un seul endroit. Voir la gestion des erreurs en VBA pour le schéma qui l'entoure.
Pourquoi un GET renvoie les données d'hier
MSXML2.XMLHTTP passe par WinINet, et WinINet tient un cache. Si la réponse du serveur autorise la mise en
cache, ou n'en dit rien, un GET répété vers la même URL peut recevoir sa réponse du cache sans jamais atteindre
le serveur. La macro s'exécute, le statut vaut 200, et les taux de change datent de ce matin.
Trois issues, de la meilleure à la pire :
- Utilisez
ServerXMLHTTPouWinHttpRequest, qui n'ont pas de cache. - Si vous devez rester sur
XMLHTTP(pour sa gestion du proxy), obligez le cache à interroger de nouveau le serveur en envoyant une date très ancienne :http.setRequestHeader "If-Modified-Since", "Sat, 01 Jan 2000 00:00:00 GMT". - Rendez chaque URL unique avec un paramètre jetable, comme
"&_=" & Format(Now, "yyyymmddhhnnss"). Cela fonctionne, mais certaines API rejettent les paramètres qu'elles ne connaissent pas.
Le signe révélateur du cache : une requête qui répond instantanément avec exactement les mêmes données que la fois précédente, alors que la même URL dans un navigateur affiche quelque chose de plus récent.
Les délais d'expiration, et pourquoi une requête peut figer Excel
Le False de http.Open "GET", url, False rend la requête synchrone : VBA attend sur cette ligne jusqu'à
l'arrivée de la réponse. Pendant cette attente, Excel ne peut ni se redessiner ni réagir, et Windows affiche la
fenêtre comme Ne répond pas. Une API lente se transforme en Excel figé ; une API morte, sans délai
d'expiration, peut le figer longtemps.
setTimeouts prend quatre valeurs en millisecondes : résolution du nom, connexion, envoi et réception.
Réglez-les sur des valeurs adaptées à l'API. 5000, 5000, 10000, 30000 signifie : abandonner si le serveur ne
peut être trouvé ou joint en cinq secondes, ou s'il n'a pas répondu en trente. XMLHTTP n'a pas de méthode
équivalente, ce qui est une raison de plus de préférer ServerXMLHTTP pour tout ce qu'un utilisateur attend.
Pour une boucle qui enchaîne de nombreuses requêtes, mettez à jour la barre d'état
entre les appels afin que l'utilisateur voie la progression. Les requêtes asynchrones existent (True comme
troisième argument), mais les surveiller depuis VBA exige une boucle DoEvents et ajoute plus de sources de
panne qu'elle n'en retire ; gardez des requêtes synchrones et courtes.
Accents illisibles : décoder les octets vous-même
responseText décode les octets avec le jeu de caractères que le serveur déclare dans son en-tête
Content-Type, et suppose de l'UTF-8 quand le serveur n'en déclare aucun. La plupart des API modernes envoient
de l'UTF-8 et le disent, et tout fonctionne. Un serveur plus ancien qui envoie du Windows-1252, de
l'ISO-8859-1 ou du Shift_JIS sans le dire arrive sous la forme München, ou de points d'interrogation et
de petits carrés.
Dans ce cas, laissez responseText de côté, prenez les octets bruts et décodez-les avec le bon jeu de
caractères :
Function BytesToText(ByVal bytes As Variant, ByVal charset As String) As String
With CreateObject("ADODB.Stream")
.Type = 1 ' binaire
.Open
.Write bytes
.Position = 0
.Type = 2 ' texte
.Charset = charset ' "windows-1252", "iso-8859-1", "shift_jis"
BytesToText = .ReadText
.Close
End With
End Function
body = BytesToText(http.responseBody, "windows-1252")
Un piège pendant le débogage : ne jugez pas le texte dans la fenêtre Exécution. L'éditeur VBA ne sait afficher
que les caractères de la page de codes système de Windows : un texte japonais correct s'affiche donc en ???
sur votre Windows français, et un texte français correct peut s'afficher de travers sur un Windows japonais.
Écrivez la chaîne dans une cellule ; la cellule montre la vérité.
Envoyer un POST avec un corps JSON
Un POST, c'est le même appel avec une méthode, un type de contenu et un corps :
http.Open "POST", "https://api.example.com/orders", False
http.setRequestHeader "Content-Type", "application/json"
http.send "{""sku"":""A-100"",""qty"":3}"
Le piège consiste à construire ce corps en collant des nombres dans une chaîne. VBA convertit un nombre en
texte selon les paramètres régionaux de Windows : sur votre Windows français (comme sur un poste allemand
ou espagnol), "{""price"":" & 3.5 & "}" produit {"price":3,5}, qui n'est pas du JSON valide. La même macro
fonctionne à New York et échoue à Paris ou à Munich. Convertissez les nombres avec Trim$(Str$(x)), qui
utilise toujours un point (voir VBA Str), ou mieux, construisez le corps avec une
bibliothèque JSON comme le montre VBA JSON.
Chaînes de requête et clés d'API
Les valeurs placées dans une URL doivent être encodées en pourcentage : une espace, une esperluette ou un
caractère accentué dans un paramètre de requête casse la requête ou la modifie en silence. Excel 2013 et
versions ultérieures disposent d'une fonction pour cela, qui encode les lettres accentuées en UTF-8 :
Zürich devient ainsi Z%C3%BCrich :
url = "https://api.example.com/search?city=" & _
Application.WorksheetFunction.EncodeURL(Range("B2").Value)
' B2 = Zurich & Geneva -> city=Zurich%20%26%20Geneva
Les clés d'API vont dans un en-tête, généralement http.setRequestHeader "Authorization", "Bearer " & apiKey.
Elles ne vont pas dans le code. Quiconque possède le classeur peut ouvrir l'éditeur VBA, et un mot de passe de
projet VBA n'est pas une vraie protection. Lisez la clé à l'exécution, depuis un fichier du profil de
l'utilisateur ou depuis une variable d'environnement avec Environ, afin de pouvoir
partager le classeur sans partager la clé.
Le parti pris : une seule fonction de requête, trois vérifications
La plupart des macros HTTP défaillantes ne se trompent pas sur HTTP. Elles sautent l'une des trois
vérifications que la bibliothèque ne fera pas à votre place : la réponse est-elle arrivée à temps, le
serveur a-t-il dit oui, et le texte est-il correctement décodé. Écrivez donc une seule fonction de requête
qui fixe les délais, vérifie le statut et décode délibérément, et faites-en le seul endroit du projet qui
appelle send.
Pour l'objet, partez par défaut sur MSXML2.ServerXMLHTTP.6.0 : pas de cache périmé, de vrais délais
d'expiration. Ne passez à MSXML2.XMLHTTP.6.0 que si vos utilisateurs sont derrière un proxy que vous ne
pouvez pas configurer, et ajoutez alors l'en-tête If-Modified-Since. Et si tout ce qu'il vous faut, c'est
récupérer le même tableau à chaque actualisation, sans aucune logique autour, envisagez Données > À partir
du web de Power Query avant d'écrire la moindre ligne de VBA.
Comment ExcelMaster aide
Les macros d'API échouent sur les machines des autres : un proxy que vous n'avez jamais vu, un Windows réglé dans une autre langue, un serveur qui répond lentement le lundi matin.
ExcelMaster écrit le code de requête pour le classeur qu'il a sous les yeux, vérifie le statut et le résultat décodé avant que quoi que ce soit n'atteigne vos cellules, et vous montre ce que l'API a réellement renvoyé quand cela ne correspond pas à ce que vous attendiez.
Questions fréquentes
Comment faire une requête HTTP GET en Excel VBA ?
Créez MSXML2.ServerXMLHTTP.6.0 avec CreateObject, appelez .Open "GET", url, False, puis .send,
vérifiez .Status et lisez .responseText. Aucune référence n'est nécessaire.
Quelle est la différence entre XMLHTTP et ServerXMLHTTP ?
XMLHTTP utilise WinINet : il suit les paramètres proxy de l'utilisateur, peut mettre en cache les réponses
GET et n'a aucun réglage de délai d'expiration. ServerXMLHTTP utilise WinHTTP : pas de cache et de vrais
délais d'expiration, mais vous devrez peut-être définir un proxy avec setProxy.
Pourquoi ma requête VBA renvoie-t-elle d'anciennes données ?
MSXML2.XMLHTTP peut répondre à un GET répété depuis le cache WinINet. Passez à ServerXMLHTTP, ou envoyez
une ancienne date If-Modified-Since avec setRequestHeader avant send.
Pourquoi VBA ne déclenche-t-il pas d'erreur sur un 404 ou un 500 ?
Parce que la requête elle-même a réussi : le serveur a répondu. Seuls les échecs de transport, comme l'absence
de réseau ou un délai dépassé, déclenchent une erreur d'exécution. Vérifiez .Status après chaque send.
Pourquoi le texte de la réponse est-il illisible ?
Le serveur a envoyé du texte dans un encodage qu'il n'a pas déclaré, et responseText a supposé de l'UTF-8.
Décodez .responseBody avec ADODB.Stream et le bon Charset.
Testé dans
Testé dans : Excel 365 (Windows 11), VBA 7.1 — vérifié le 05/10/2026.
Guides connexes : VBA JSON · Web scraping en VBA · VBA CreateObject · Gestion des erreurs en VBA · VBA On Error · VBA Str · VBA Environ · Barre d'état en VBA (StatusBar)
