AliJSONRPC
Rocou
Membre
Bonjour,
Je m'adresse plus particulièrement à Ali car je tente d'utiliser son "FrameWork" AliJSONRPC
Tout semble se dérouler correctement mais j'obtiens l'erreur suivante:
"Unrecognised leading character"
Je débute totalement, je ne connaissais même pas l'existence de JSON il y a encore quelques jours.
Mon script php sur mon serveur renvoie les données suivantes:
{"id":"1","nom":"Alexis","autorisation":"t"},{"id":"2","nom":"Hubert","autorisation":"t"}
Ces données sont issues d'une requète SQL et formaté en JSON par la fonction sql2json()
Je ne vois pas trop ce qui peut clocher...
Je m'adresse plus particulièrement à Ali car je tente d'utiliser son "FrameWork" AliJSONRPC
Tout semble se dérouler correctement mais j'obtiens l'erreur suivante:
"Unrecognised leading character"
Je débute totalement, je ne connaissais même pas l'existence de JSON il y a encore quelques jours.
Mon script php sur mon serveur renvoie les données suivantes:
{"id":"1","nom":"Alexis","autorisation":"t"},{"id":"2","nom":"Hubert","autorisation":"t"}
Ces données sont issues d'une requète SQL et formaté en JSON par la fonction sql2json()
Je ne vois pas trop ce qui peut clocher...
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Vérifie donc l'encodage du fichier .php, l'encodage utilisé pour la connexion à la base de donnée, l'encodage utilisé dans la base de donnée pour ainsi unifier le tout et au besoin convertir les chaines dans le bon encodage
Ha oui, je n'avais pas pensé à cela, je regarde de ce côté, merci.
Et c'est vrai que ce que tu retournes avec ton code PHP n'est pas un objet JSON valide (ce qui est bizarre vu que tu l'as généré avec sql2json mais bon) : tu peux le vérifier avec des sites comme http://www.jsonlint.com/
En effet, ton texte JSON commence par un objets puisqu'il débute avec une accolade ouvrante. Ton objet se termine un peu plus loin avec l'accolade fermante... mais est suivi d'une virgule, et d'un autre objet (autre accolade ouvrante), donc le JSON retourné contient 2 objets, alors qu'il ne devrait représenter qu'un seul objet en racine (c'est un peu si dans un arbre XML, tu avais deux noeuds racines et non un seul).
En fait pour ton cas si tu veux retourner 2 objets il faut les encapsuler dans un tableau et retourner ce tableau de 2 objets (ce qui revient en JSON à entourer ta réponse entre "[" et "]")
Merci pour tes précisions.
En fait, cela n'a rien de bizarre, je me demandais à quoi servait les "[" et "]" alors j'avais modifié sql2json pour les supprimer
Bon, je vais tout reprendre mais une fois que mon serveur aura redémarré (un idiot à voulu récupéré la table sur laquelle était posé le macMini et le câble de l'alimentation s'était déconnecté et comme je suis à 70 bornes de la machine, faire un diagnostique à distance était un peu laborieux )
Encore merci.
Crash de mon application avec comme erreur:
-[__NSArrayM objectForKey:]: unrecognized selector sent to instance 0x4e6b9d0
2011-03-22 15:34:53.714 Bom[88466:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM objectForKey:]: unrecognized selector sent to instance 0x4e6b9d0'
au débugger cela semble se passer à l'appel de cette fonction (totalement copiée sur une des tiennes):
-(void)afficheChauffeursWithDelegate:(id)delegate callback:(SEL)callback
{
service callMethodWithNameAndParams:@"connectionBD",nil]<br /> setDelegate:delegate callback:callback resultClass:[Chauffeur class;
}
Je suppose que je ne reçois pas de données correctes en provenance du serveur mais comment afficher ce que je reçois (les données brutes) afin de comprendre ce qui se passe?
Ceci dit si tu regardes la callstack qu'il t'affiche quand tu crash, tu devrais avoir la pile d'appel aux fonctions et voir exactement à quelle ligne ça crash et dans quelle méthode. Est-ce dans mon framework AliJSONRPC, et si oui dans quelle méthode et à quelle ligne (et qu'est ce qui est reçu à ce moment), est-ce dans ta méthode de delegate ? Est-ce que ce n'est pas ton delegate qui n'existe plus (par exemple si tu as créé un objet autorelease et qui a donc été releasé entre le moment où tu as démarré la requête et celui où tu as reçu la réponse car une requête réseau n'est pas immédiate) et du coup il essaye d'envoyer un message à un objet qui a été détruit ? Est-ce ta resultClass Chauffeur qui n'implémente pas la méthode initWithJson (que tu dois implémenter pour permettre de convertir l'objet JSON (NSArray, NSDictionary, ...) reçu en un objet Chauffeur si tu veux l'utiliser en tant que resultClass -- bien qu'il me semblait avoir mis des sécurités/assertions si ça n'était pas le cas) ?
Alors voici la callstack que je n'arrive pas à interpréter:
*** Call stack at first throw:
(
0 CoreFoundation 0x00ddd5a9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x00f31313 objc_exception_throw + 44
2 CoreFoundation 0x00ddf0bb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x00d4e966 ___forwarding___ + 966
4 CoreFoundation 0x00d4e522 _CF_forwarding_prep_0 + 50
5 Bom 0x00008e1e -[JSONRPCResponseHandler connectionDidFinishLoading:] + 946
6 Foundation 0x0006f112 -[NSURLConnection(NSURLConnectionReallyInternal) sendDidFinishLoading] + 108
7 Foundation 0x0006f06b _NSURLConnectionDidFinishLoading + 133
8 CFNetwork 0x01386492 _ZN19URLConnectionClient23_clientDidFinishLoadingEPNS_26ClientConnectionEventQueueE + 220
9 CFNetwork 0x014516e1 _ZN19URLConnectionClient26ClientConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XClientEvent18XClientEventParamsEl + 293
10 CFNetwork 0x014519cf _ZN19URLConnectionClient26ClientConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XClientEvent18XClientEventParamsEl + 1043
11 CFNetwork 0x0137cc84 _ZN19URLConnectionClient13processEventsEv + 100
12 CFNetwork 0x0137cad3 _ZN17MultiplexerSource7performEv + 251
13 CoreFoundation 0x00dbe8ff __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
14 CoreFoundation 0x00d1c88b __CFRunLoopDoSources0 + 571
15 CoreFoundation 0x00d1bd86 __CFRunLoopRun + 470
16 CoreFoundation 0x00d1b840 CFRunLoopRunSpecific + 208
17 CoreFoundation 0x00d1b761 CFRunLoopRunInMode + 97
18 GraphicsServices 0x017341c4 GSEventRunModal + 217
19 GraphicsServices 0x01734289 GSEventRun + 115
20 UIKit 0x002dbc93 UIApplicationMain + 1160
21 Bom 0x0000231c main + 102
22 Bom 0x000022ad start + 53
23 ??? 0x00000001 0x0 + 1
)
terminate called after throwing an instance of 'NSException'
Pour le reste, j'ai scrupuleusement copié tes méthodes (comme tu peux le voir, je n'ai même pas encore modifié les commentaires ).
Ma resultClass Chauffeur est la suivante:
Merci pour le temps passé.
Niveau code, je suis loin d'être à ton niveau, beaucoup de chose sont encore obscures. Cela dit, j'ai depuis toujours, évité tout code qui demande de la réflexion à la relecture
Sinon, je sais maintenant que le serveur retourne quelque chose de correct car tout fonctionne très bien en utilisant JSON.h
Cependant je pense savoir ce qui cloche (et c'est vrai que j'ai oublié de mettre une sécurité sur ce cas qui ne doit pas arriver sur tu as un vrai serveur JSONRPC en face) : ce que tu renvoies c'est du JSON, mais pas du JSON-RPC !
Un vrai WebService JSONRPC reçoit des requêtes formattées en JSON avec une certaine structure (le nom de la méthode dans une clé donnée, les paramètres de la méthode dans une autre, etc) et retourne les résultats dans un JSON également formatté d'une certaine manière (cf http://json-rpc.org/wiki/specification)
Or toi tu retournes directement le résultat (ton objet encodé en JSON) alors que tu devrais encapsuler ça dans un JSON contenant les clés "id", "result" et "error" qui te permettent de formatter la réponse correctement et de prévoir les cas d'erreur et tout.
Bravo, c'est ça!
Finalement le JSON est plus complexe que je ne le pensais après avoir lu (survolé) la définition sur wikipedia (français).
Ne pas confondre JSON et JSON-RPC.
- JSON, c'est un format de sérialisation des objets standards, une notation textuelle des données. JSON = JavaScript Object Notation
- RPC, qui veut dire "Remote Procedure Call", est un mécanisme permettant d'appeler (call) des méthodes (procédures) distantes (remote), par exemple d'appeler des méthodes d'un WebService depuis un client (genre un iPhone)
Les 2 acronymes décrivent des choses distinctes, l'une est une représentation de données, l'autre un mécanisme pour communiquer entre un client et un serveur pour appeler des méthodes distantes. Tu peux utiliser le JSON tout seul complètement à l'extérieur du contexte JSON-RPC, et les mécanismes de RPC peuvent utiliser autre chose que du JSON (par exemple du XML) pour transporter les informations indiquant la méthode à appeler et les paramètres et le retour.
Le JSON-RPC, c'est donc l'alliance des deux technos : utiliser le JSON comme notation/représentation/sérialisation pour envoyer et recevoir des RPC (appeler des procédures distantes et recevoir le résultat).
Quand tu fais du JSON-RPC, tu utilises la notation JSON dans ta requête RPC pour indiquer la méthode que tu veux appeler et les paramètres à passer à cette méthode, et le serveur " s'il respecte bien le standard JSON-RPC " te retourne la réponse sous la forme d'un objet JSON également, qui consiste en un objet ayant une clé "id" reprenant l'identifiant de la requête (pour que tu puisses retrouver à quelle requête correspond la réponse), une clé "result" contenant le résultat (la réponse) de la requête, et une éventuelle clé "error" contenant l'erreur en cas d'erreur lors de l'appel (méthode inexistante, paramètres manquants ou incorrects, ...)
C'est tout ça que gère mon framework : la construction de la requête pour appeler la méthode que tu demandes et lui passer les paramètres, l'envoi de la requête, la réception de la réponse, le décodage/extraction de ladite réponse ou du code d'erreur le cas échéant, et la distribution de cette réponse ou erreur au delegate.
---
Il existe d'autres standards pour communiquer à un WebService que le JSON-RPC. Tu as le XML-RPC qui est le même principe mais utilisant du XML plutôt que du JSON pour passer le nom de la méthode, les paramètres, et récupérer le résultat ou l'erreur. Tu as le REST, où les paramètres sont passés dans l'URL directement genre "/webservice/getChauffeur/id/5", tu as le SOAP qui passe les paramètres un peu comme RPC formattés dans le corps de la requête envoyée en POST, etc, etc.
L'avantage du JSON-RPC est qu'il est relativement léger (JSON est plus léger que XML) et simple à mettre en oeuvre. La seule chose que tu as à prévoir côté serveur c'est d'encapsuler ta réponse JSON dans un objet JSON ayant les clés "id","result" et éventuellement "error" si erreur il y a.
Une autre solution assez sympa est le JSON-REST où tu passes les paramètres directement dans l'URL et la réponse t'es directement retournée en JSON. Mais du coup il faut faire du URL-Rewriting côté serveur (ou utiliser des frameworks comme Zend pour gérer le REST) et côté gestion d'erreurs il faut penser à traiter les cas d'erreur (ce que JSON-RPC te force un peu à faire en encapsulant la réponse dans un objet JSON [tt]{"id":"...","result":objetRetournéParTaMethodeEnJson,"error":"objet décrivant l'erreur si erreur il y a eu"}[/tt]
- Je vérifie maintenant que le JSON que tu reçoit respecte la spec, pour éviter que le crash que tu as eu se reproduise si ton serveur retourne un objet non conforme à la spec (maintenant à la place ça remonte une erreur de type JSONRPCInternalError et met un NSLog pour expliquer le pb)
- Commit d'un ajout que j'avais fait il y a quelques temps d'un mécanisme d'auto-retry : en effet, en conditions réelles sur iPhone il arrive que le réseau soit coupé, d'après ce que j'ai observé parce que l'équipement réseau (puce EDGE/3G) de ton iPhone est passé en veille, ce qui fait que la requête n'est pas envoyée et qu'on reçoit une erreur "Connection Lost" dans ce genre de cas. Sauf que le fait d'avoir essayé d'envoyer la requête réveille l'équipement réseau (un peu tard) et donc qu'en réenvoyant la requête une 2e fois cette fois elle passe. Du coup dans ce cas précis j'ai automatisé le renvoi de la requête une 2e fois pour réessayer de passer. Si ça passe pas après réessai, là je remonte finalement l'erreur.
Tu peux faire un pull / update du coup sur mon github si tu veux te mettre à jour.
J'ai du préparer un contrôle en entreprise (un de plus!) qui m'a éloigné un peu de mon clavier.
Je teste à nouveau tout ça.