2010-08-06 4 views
0

J'ai créé une API qui est utilisée sur plusieurs sites. Les sites clients appellent le serveur avec file_get_contents ou curl et accèdent à une URL comme "http://www.myserver.com/api/record.php?some=thing". Le client passe l'appel et attend que l'API réponde avant de traiter le reste de la page. Cependant, certaines fois, aucune sortie de l'API n'est requise par le client. Je me demande s'il existe un moyen pour le serveur de produire quelque chose pour que le client ne l'attende pas pendant que le processus du serveur exécute ce qu'il doit faire. Quelque chose comme 'page done', donc le client n'attend plus le chargement, mais le script du serveur est toujours en cours d'exécution pendant une seconde pendant qu'il insère des entrées de base de données. J'ai lu que les fonctions de contrôle de processus sont uniquement destinées à l'interface de ligne de commande et qu'elles ne doivent pas être utilisées dans un environnement de serveur Web. Il est donc hors de question de créer un nouveau processus.PHP - Envoi d'une réponse rapide de l'API au client pendant que le serveur fonctionne

Des suggestions? Je sais que faire l'appel de manière asynchrone avec javascript fonctionnerait, mais nous avons trouvé que les accès PHP étaient plus fiables que JS.

Merci beaucoup!

+0

Dans le dernier paragraphe sur les appels asynchrones, vous référez-vous à l'accès à l'API en tant que client droit? – Nate

Répondre

0

La connexion entre votre script et votre API est la chose délicate; vous devez le terminer pour le curl ou file_get_contents pour retourner. (Vous pouvez regarder dans le curl_multi_ asynchrone * fonctions ou faire votre propre prise de manipulation comme artefacto suggéré)

Une option serait de mettre le traitement back-end dans un processus backgrounded, comme ceci:

$desc = array(); // fd descriptors 
$proc = proc_open("/bin/sleep 60 &",$desc,$pipes); 

où le sommeil est juste pour la preuve de concept. Il vit heureux, après la connexion est terminée. L'inconvénient est que si vous avez un fd est connecté, le processus enfant mourra avec le parent, vous devez donc pousser les données via la ligne de commande ou $ env (5e argument à proc_open)

+0

Bien que ce ne soit pas la solution que j'ai utilisée, c'est la meilleure approche. Vous devrez rapidement retourner et fermer la connexion, mais avant cela, démarrez un processus en arrière-plan ou mettez-le en file d'attente pour qu'un autre processus s'exécute. –

-1

Vous pouvez le faire comme ceci:

ob_start(); 

//create and output any output to be sent to the browser. 

// get the size of the output 
$size = ob_get_length(); 

// send headers to tell the browser to close the connection 
header("Content-Length: $size"); 
header('Connection: close'); 

// flush all output 
ob_end_flush(); 
ob_flush(); 
flush(); 

//do any post-processing here. 
+0

Un test rapide montre qu'un navigateur ou apache ne ferme pas la connexion et arrête le chargement, basé sur ces lignes, jusqu'à ce que le script se termine, donc probablement curl et file_get_contents attendra également que la connexion soit fermée. – mvds

+0

ps. le downvote n'était pas le mien, je pense que l'idée pourrait/devrait être capable de travailler. – mvds

+0

C'était à moi. 'Connection: close' indique seulement au client que la connexion doit être fermée après l'envoi du corps de la requête (l'alternative étant keep-alive, qui garderait la connexion ouverte au cas où le client voudrait envoyer une autre requête). – Artefacto

0

modifier: penser à nouveau, vous auriez aucun avantage de faire une demande de async. Faites simplement une demande normale avec fsockopen et tuez-la après que fwrite a terminé les en-têtes.

Vous pouvez simplement faire une demande HEAD pour signaler que vous ne voulez pas le corps de la réponse - cela permettra d'économiser quelques voyages. En principe, vous pouvez créer un async request. Après avoir écrit les en-têtes, vous devez vous assurer qu'ils ont été correctement envoyés. À ce stade, vous pouvez interrompre la connexion et faire confiance au côté serveur ignore_user_abort. (Je ne suis pas sûr que cela fonctionnera avec tous les serveurs Web, cependant, il est possible que la demande n'atteigne jamais PHP après l'abandon prématuré d'un utilisateur).

Questions connexes