[RESOLU] JSON - Problème format de réception sur requête GET

Bonjour à tous,

J’essaie de récupérer, depuis une API, des données de transport de la RATP en temps réel.
J’ai des erreurs, donc j’ai uploader un code assez simple (modifié depuis un exemple), sur un NodeMCU:

#include <ESP8266WiFi.h>

// Wi-Fi Settings
const char* ssid = "xxxx";
const char* password = "xxxx";
String readString;

char serverName[] = "api-ratp.pierre-grimaud.fr";  // server's address

WiFiClient client;

//////////////////////

void setup(){

  WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {
 delay(500);
  }
  
  Serial.begin(9600); 
  Serial.println("client readString test 11/04/13"); // so I can keep track of what is loaded
  Serial.println("Send an e in serial monitor to test"); // what to do to test
  Serial.println();
}

void loop(){
  // check for serial input
  if (Serial.available() > 0) //if something in serial buffer
  {
    byte inChar; // sets inChar as a byte
    inChar = Serial.read(); //gets byte from buffer
    if(inChar == 'e') // checks to see byte is an e
    {
      sendGET(); // call sendGET function below when byte is an e
    }
  }  
} 

//////////////////////////

void sendGET() //client function to send/receive GET request data.
{
  if (client.connect(serverName, 80)) {  //starts client connection, checks for connection
    Serial.println("connected");
    client.println("GET /v3/schedules/bus/96/porte+des+lilas+metro/R?_format=json HTTP/1.1"); //download text
    client.println("Host: api-ratp.pierre-grimaud.fr");
    client.println("Content-Type: text/plain");
    client.println("Connection: close");  //close 1.1 persistent connection  
    client.println(); //end of get request
  } 
  else {
    Serial.println("connection failed"); //error message if no client connect
    Serial.println();
  }

  while(client.connected() && !client.available()) delay(1); //waits for data
  while (client.connected() || client.available()) { //connected or data available
    char c = client.read(); //gets byte from ethernet buffer
    readString += c; //places captured byte in readString
  }

  //Serial.println();
  client.stop(); //stop client
  Serial.println("client disconnected.");
  Serial.println("Data from server captured in readString:");
  Serial.println();
  Serial.print(readString); //prints readString to serial monitor 
  Serial.println();  
  Serial.println();
  Serial.println("End of readString");
  Serial.println("==================");
  Serial.println();
  readString=""; //clear readString variable

}

Le problème est que dans la console, je reçois un bout de page HTML :

client readString test 11/04/13
Send an e in serial monitor to test

connected
client disconnected.
Data from server captured in readString:

HTTP/1.1 301 Moved Permanently
Date: Tue, 02 May 2017 15:00:23 GMT
Server: Apache/2.4.10 (Debian)
Location: https://api-ratp.pierre-grimaud.fr/v3/schedules/bus/96/porte+des+lilas+metro/R?_format=xml
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

25c
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="refresh" content="1;url=https://api-ratp.pierre-grimaud.fr/v3/schedules/bus/96/porte+des+lilas+metro/R?_format=xml" />

        <title>Redirecting to https://api-ratp.pierre-grimaud.fr/v3/schedules/bus/96/porte+des+lilas+metro/R?_format=xml</title>
    </head>
    <body>
        Redirecting to <a href="https://api-ratp.pierre-grimaud.fr/v3/schedules/bus/96/porte+des+lilas+metro/R?_format=xml">https://api-ratp.pierre-grimaud.fr/v3/schedules/bus/96/porte+des+lilas+metro/R?_format=xml</a>.
    </body>
</html>
0



End of readString
==================

Et non pas un JSON, comme cela apparaît avec une requête dans un navigateur:
https://api-ratp.pierre-grimaud.fr/v3/schedules/bus/96/porte+des+lilas+metro/R?_format=json
Qui donne :

{
    "result": {
        "schedules": [
            {
                "message": "0 mn",
                "destination": "Porte des Lilas"
            },
            {
                "message": "3 mn",
                "destination": "Porte des Lilas"
            }
        ]
    },
    "_metadata": {
        "call": "GET /schedules/bus/96/porte+des+lilas+metro/R",
        "date": "2017-05-02T17:01:51+02:00",
        "version": 3
    }
}

Pourtant cette requête marche sur des exemples de JSON en ligne, comme https://jsonplaceholder.typicode.com/comments?postId=1 par exemple.

Avez vous une idée du problème ? Est ce que c’est le format du JSON sur le site api-ratp.pierre-grimaud.fr ? ou faut-il rajouter des requêtes dans le “GET” ?

Merci d’avance !

baba

Re-bonjour !

Hmmm, peut être que ma question ne concerne pas directement l’Arduino… ::slight_smile:
En fait j’avais essayé d’utiliser la librairie ArduinoJsonParser, mais j’avais un problème de “Parsing failed !”.
Je pense donc que le problème vient du format de la reponse au “GET”, que j’explique au dessus.

Baba

Bonjour,

Le problème tient en 1 seule lettre 's'.

Dans ton code :
if (client.connect(serverName, 80))
Tu fais ta requête sur le port 80 et donc en HTTP

Dans ton navigateur, tu saisis une URL en HTTPS.

Donc avec ton code, le serveur te renvoie une réponse 301 pour te rediriger vers l'URL en HTTPS.

Si tu essaie la requête ci-dessous dans ton navigateur :
http://api-ratp.pierre-grimaud.fr/v3/schedules/bus/96/porte+des+lilas+metro/R?_format=json

Et que tu regardes les échanges réseau, tu verras que tu obtiens aussi une réponse 301 que ton navigateur interprète et donc il refait une demande sur l'URL en HTTPS.

Comme cela est géré automatiquement par ton navigateur, tu as l'impression que tu obtiens la réponse JSON à ta requête initiale mais ce n'est pas le cas. D'ailleurs, si tu regardes l'URL dans ton navigateur, tu verras qu'elle a changée, tu es passé de http://... à https://...

Bonjour bigben99,

Merci pour ta réponse !

Alors effectivement suite à ta remarque, j’ai cherché autour de cette question de HTTPS… Et j’ai pu résoudre mon problème !

Le serveur (client ?) utilise bien une connexion httpS.

J’ai d’abord essayé de seulement modifier le port de connexion de 80 à 443 (lecture de ce forum), mais j’ai eu une erreur en réponse :

 connected
client disconnected.
Data from server captured in readString:

HTTP/1.1 400 Bad Request
Date: Thu, 04 May 2017 15:20:24 GMT
Server: Apache/2.4.10 (Debian)
Content-Length: 455
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.

Reason: You're speaking plain HTTP to an SSL-enabled server port.

 Instead use the HTTPS scheme to access this URL, please.

</p>
<hr>
<address>Apache/2.4.10 (Debian) Server at api-ratp.pierre-grimaud.fr Port 443</address>
</body></html>


End of readString

J’ai donc cherché un peu et je suis tombé sur cette discussion. Il faut donc ajouter aussi ajouter la librairie WiFiClientSecure.h et créer un ** WiFiClientSecure client** à la place d’un ** WiFiClient client**

Voici donc le code qui fonctionne :

 #include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>

// Wi-Fi Settings
const char* ssid = "xxxx";
const char* password = "xxxx";
String readString;

char serverName[] = "api-ratp.pierre-grimaud.fr";  // server's address

WiFiClientSecure client;

//////////////////////

void setup(){

  WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {
 delay(500);
  }
  
  Serial.begin(9600); 
  Serial.println("client readString test 11/04/13"); // so I can keep track of what is loaded
  Serial.println("Send an e in serial monitor to test"); // what to do to test
  Serial.println();
}

void loop(){
  // check for serial input
  if (Serial.available() > 0) //if something in serial buffer
  {
    byte inChar; // sets inChar as a byte
    inChar = Serial.read(); //gets byte from buffer
    if(inChar == 'e') // checks to see byte is an e
    {
      sendGET(); // call sendGET function below when byte is an e
    }
  }  
} 

//////////////////////////

void sendGET() //client function to send/receive GET request data.
{
  if (client.connect(serverName, 443)) {  //starts client connection, checks for connection
    Serial.println("connected");
    client.println("GET /v3/schedules/bus/96/porte+des+lilas+metro/R?_format=json HTTP/1.1"); //download text
    client.println("Host: api-ratp.pierre-grimaud.fr");
    client.println("Connection: close");  //close 1.1 persistent connection  
    client.println(); //end of get request
  } 
  else {
    Serial.println("connection failed"); //error message if no client connect
    Serial.println();
  }

  while(client.connected() && !client.available()) delay(1); //waits for data
  while (client.connected() || client.available()) { //connected or data available
    char c = client.read(); //gets byte from ethernet buffer
    readString += c; //places captured byte in readString
  }

  //Serial.println();
  client.stop(); //stop client
  Serial.println("client disconnected.");
  Serial.println("Data from server captured in readString:");
  Serial.println();
  Serial.print(readString); //prints readString to serial monitor 
  Serial.println();  
  Serial.println();
  Serial.println("End of readString");
  Serial.println("==================");
  Serial.println();
  readString=""; //clear readString variable

}

Merci encore bigben99

Braba