HTTP Saber (Da Mao Wang), un client HTTP PHP hautes performances de Swoole人性化组件库
, est basé sur la coroutine native de Swoole, prend en charge plusieurs styles d'opérations et fournit des solutions hautes performances en bas, permettant aux développeurs de se concentrer sur les fonctionnalités. développement, du traditionnel Libre du blocage synchrone et de la configuration encombrante de Curl.
Document anglais
La meilleure façon d'installer est via le gestionnaire de packages Composer :
composer require swlib/saber
La couche inférieure de Swoole implémente la planification des coroutines et la couche métier n'a pas besoin d'en être consciente . Les développeurs peuvent utiliser l'écriture de code synchrone pour obtenir l'effet d'E/S asynchrones et de performances ultra élevées sans s'en rendre compte, évitant ainsi la logique de code discret et . un recouvrement excessif provoqué par les rappels asynchrones traditionnels rend le code impossible à maintenir.
Il doit être utilisé dans onRequet
, onReceive
, onConnect
et d'autres fonctions de rappel d'événement, ou enveloppé avec le mot-clé go ( swoole.use_shortname
est activé par défaut).
go ( function () {
echo SaberGM:: get ( ' http://httpbin.org/get ' );
})
Conditionnement automatique des données : les données entrantes seront automatiquement converties au format de type spécifié par le type de contenu.
La valeur par défaut est
x-www-form-urlencoded
, et d'autres formats tels quejson
sont également pris en charge.
SaberGM
:= Saber Global Manager
. Si vous pensez que le nom de la classe est un peu long, vous pouvez utiliser class_alias
pour choisir vous-même un alias. Il est recommandé d'utiliser la méthode de génération d'instances dans le service et d'utiliser SaberGM
comme raccourci.
SaberGM:: get ( ' http://httpbin.org/get ' );
SaberGM:: delete ( ' http://httpbin.org/delete ' );
SaberGM:: post ( ' http://httpbin.org/post ' , [ ' foo ' => ' bar ' ]);
SaberGM:: put ( ' http://httpbin.org/put ' , [ ' foo ' => ' bar ' ]);
SaberGM:: patch ( ' http://httpbin.org/patch ' , [ ' foo ' => ' bar ' ]);
Service proxy d'API applicable
$ saber = Saber:: create ([
' base_uri ' => ' http://httpbin.org ' ,
' headers ' => [
' Accept-Language ' => ' en,zh-CN;q=0.9,zh;q=0.8 ' ,
' Content-Type ' => ContentType:: JSON ,
' DNT ' => ' 1 ' ,
' User-Agent ' => null
]
]);
echo $ saber -> get ( ' /get ' );
echo $ saber -> delete ( ' /delete ' );
echo $ saber -> post ( ' /post ' , [ ' foo ' => ' bar ' ]);
echo $ saber -> patch ( ' /patch ' , [ ' foo ' => ' bar ' ]);
echo $ saber -> put ( ' /put ' , [ ' foo ' => ' bar ' ]);
La session enregistrera automatiquement les informations sur les cookies et sa mise en œuvre est terminée au niveau du navigateur.
$ session = Saber:: session ([
' base_uri ' => ' http://httpbin.org ' ,
' redirect ' => 0
]);
$ session -> get ( ' /cookies/set?foo=bar&k=v&apple=banana ' );
$ session -> get ( ' /cookies/delete?k ' );
echo $ session -> get ( ' /cookies ' )-> body ;
Remarque : Une solution d'optimisation de redirection simultanée est utilisée ici. Plusieurs redirections sont toujours simultanées et ne dégénéreront pas en une seule requête dans la file d'attente.
$ responses = SaberGM:: requests ([
[ ' uri ' => ' http://github.com/ ' ],
[ ' uri ' => ' http://github.com/ ' ],
[ ' uri ' => ' https://github.com/ ' ]
]);
echo " multi-requests [ { $ responses -> success_num } ok, { $ responses -> error_num } error ]: n" . " consuming-time: { $ responses -> time } s n" ;
// multi - requests [ 3 ok , 0 error ] :
// consuming - time : 0 . 79090881347656s
// 别名机制可以省略参数书写参数名
$ saber = Saber:: create ([ ' base_uri ' => ' http://httpbin.org ' ]);
echo $ saber -> requests ([
[ ' get ' , ' /get ' ],
[ ' post ' , ' /post ' ],
[ ' patch ' , ' /patch ' ],
[ ' put ' , ' /put ' ],
[ ' delete ' , ' /delete ' ]
]);
Prend actuellement en charge l'analyse rapide des données dans quatre formats : json
, xml
, html
et url-query
[ $ json , $ xml , $ html ] = SaberGM:: list ([
' uri ' => [
' http://httpbin.org/get ' ,
' http://www.w3school.com.cn/example/xmle/note.xml ' ,
' http://httpbin.org/html '
]
]);
var_dump ( $ json -> getParsedJsonArray ());
var_dump ( $ json -> getParsedJsonObject ());
var_dump ( $ xml -> getParsedXmlArray ());
var_dump ( $ xml -> getParsedXmlObject ( true ));
var_dump ( $ html -> getParsedDomObject ()-> getElementsByTagName ( ' h1 ' )-> item ( 0 )-> textContent );
Prend en charge les proxys HTTP et SOCKS5
$ uri = ' http://myip.ipip.net/ ' ;
echo SaberGM:: get ( $ uri , [ ' proxy ' => ' http://127.0.0.1:1087 ' ])-> body ;
echo SaberGM:: get ( $ uri , [ ' proxy ' => ' socks5://127.0.0.1:1086 ' ])-> body ;
La planification automatique sous-jacente des coroutines peut prendre en charge l'envoi asynchrone de fichiers très volumineux et la transmission de reprise au point d'arrêt.
Téléchargez trois fichiers en même temps (trois styles de paramètres
string
|array
|object
)
$ file1 = __DIR__ . ' /black.png ' ;
$ file2 = [
' path ' => __DIR__ . ' /black.png ' ,
' name ' => ' white.png ' ,
' type ' => ContentType:: MAP [ ' png ' ],
' offset ' => null , // re - upload from break
' size ' => null //upload a part of the file
];
$ file3 = new SwUploadFile (
__DIR__ . ' /black.png ' ,
' white.png ' ,
ContentType:: MAP [ ' png ' ]
);
echo SaberGM:: post ( ' http://httpbin.org/post ' , null , [
' files ' => [
' image1 ' => $ file1 ,
' image2 ' => $ file2 ,
' image3 ' => $ file3
]
]
);
Une fois que Download a reçu les données, il les écrira directement sur le disque de manière asynchrone au lieu de coller le HttpBody dans la mémoire. Par conséquent, le téléchargement n'utilise qu'une petite quantité de mémoire pour terminer le téléchargement de fichiers très volumineux . Il prend également en charge le téléchargement de reprise par point d'arrêt. définir le paramètre offset pour effectuer des téléchargements de points d’arrêt.
Téléchargement asynchrone des fonds d'écran Sabre
$ download_dir = ' /tmp/saber.jpg ' ;
$ response = SaberGM:: download (
' https://ws1.sinaimg.cn/large/006DQdzWly1fsr8jt2botj31hc0wxqfs.jpg ' ,
$ download_dir
);
if ( $ response -> success ) {
exec ( ' open ' . $ download_dir );
}
Dans les projets de robots d'exploration, il est très courant de réessayer automatiquement une demande ayant échoué, comme par exemple se reconnecter après l'expiration d'une session.
Saber
intègre cette fonctionnalité et拦截器
peuvent être utilisés pour l'améliorer.
Si retry_time
n'est pas défini mais qu'un intercepteur retry
tentative est défini, retry_time
sera défini sur 1. Si la méthode de rappel de l'intercepteur retry
renvoie false
, quel que soit retry_time
, la nouvelle tentative sera terminée lorsque false
sera renvoyé.
$ uri = ' http://eu.httpbin.org/basic-auth/foo/bar ' ;
$ res = SaberGM:: get (
$ uri , [
' exception_report ' => 0 ,
' retry_time ' => 3 ,
' retry ' => function ( Saber Request $ request ) {
echo " retry... n" ;
$ request -> withBasicAuth ( ' foo ' , ' bar ' ); //发现失败后添加验证信息
if ( ' i don not want to retry again ' ) {
return false ; // shutdown
}
}
]
);
echo $ res ;
Parfois, les ressources HTTP ne changent pas toujours. Nous pouvons apprendre comment les navigateurs mettent en cache les ressources qui ne changent pas pour accélérer l'efficacité des requêtes. Saber
le fait automatiquement sans avoir à maintenir la logique de mise en cache (CURD ou lecture et écriture de fichiers) par elle-même. de toute façon, cela ne bloquera pas le serveur. Saber
n'utilise pas de mécanisme middleware car il est fortement lié à Swoole, mais la mise en cache peut utiliser内存/文件/数据库
et d'autres méthodes, donc même si elle n'a pas encore été implémentée, elle sera incluse dans Saber
la feuille de route ultérieure.
$ bufferStream = new BufferStream ();
$ bufferStream -> write ( json_encode ([ ' foo ' => ' bar ' ]));
$ response = SaberGM:: psr ()
-> withMethod ( ' POST ' )
-> withUri ( new Uri ( ' http://httpbin.org/post?foo=bar ' ))
-> withQueryParams ([ ' foo ' => ' option is higher-level than uri ' ])
-> withHeader ( ' content-type ' , ContentType:: JSON )
-> withBody ( $ bufferStream )
-> exec ()-> recv ();
echo $ response -> getBody ();
Vous pouvez imprimer directement la chaîne de données renvoyée via la méthode __toString du bloc de données websocketFrame.
$ websocket = SaberGM:: websocket ( ' ws://127.0.0.1:9999 ' );
while ( true ) {
echo $ websocket -> recv ( 1 ) . "n" ;
$ websocket -> push ( " hello " );
co:: sleep ( 1 );
}
La machine de test est un MacBook Pro avec la configuration la plus basse et le serveur de requêtes est un serveur d'écho local.
6 666 requêtes complétées en 0,9 seconde , avec un taux de réussite de 100 %.
co:: set ([ ' max_coroutine ' => 8191 ]);
go ( function () {
$ requests = [];
for ( $ i = 6666 ; $ i --;) {
$ requests [] = [ ' uri ' => ' http://127.0.0.1 ' ];
}
$ res = SaberGM:: requests ( $ requests );
echo " use { $ res -> time } s n" ;
echo " success: $ res -> success_num , error: $ res -> error_num " ;
});
// on MacOS
// use 0 . 91531705856323s
// success : 6666 , error : 0
Dans les projets réels, les listes d'URL sont souvent utilisées pour configurer les requêtes, la méthode list est donc fournie pour plus de commodité :
echo SaberGM:: list ([
' uri ' => [
' https://www.qq.com/ ' ,
' https://www.baidu.com/ ' ,
' https://www.swoole.com/ ' ,
' http://httpbin.org/ '
]
]);
Dans les projets de robots d'exploration réels, nous devons souvent limiter le nombre de requêtes simultanées uniques pour éviter d'être bloquées par le pare-feu du serveur, et un paramètre max_co
peut facilement résoudre ce problème. max_co
poussera les requêtes dans la file d'attente par lots en fonction de la limite supérieure. et exécutez-les.
// max_co is the max number of concurrency request once , it ' s very useful to prevent server - waf limit .
$ requests = array_fill ( 0 , 10 , [ ' uri ' => ' https://www.qq.com/ ' ]);
echo SaberGM:: requests ( $ requests , [ ' max_co ' => 5 ])-> time . "n" ;
echo SaberGM:: requests ( $ requests , [ ' max_co ' => 1 ])-> time . "n" ;
Lorsqu'il est utilisé sur un serveur résidant en mémoire, veillez à activer manuellement l'option du pool de connexions :
$ swoole = Saber:: create ([
' base_uri ' => ' https://www.swoole.com/ ' ,
' use_pool ' => true
]);
Lorsqu'elle est utilisée via cette instance, la fonctionnalité de pool de connexions sera activée, c'est-à-dire que le client de connexion sous-jacent au site Web www.swoole.com
utilisera un pool de connexions global pour accéder, évitant ainsi la surcharge de création/connexion à chaque utilisation. .
Lorsque le paramètre est true
, la capacité du pool de connexions du site Web est illimitée . Généralement, il n'y a pas de problème et le pool de connexions à capacité illimitée a de meilleures performances.
Mais si vous l'utilisez comme service proxy d'exploration et rencontrez un grand nombre de requêtes , le nombre de clients dans le pool de connexions augmentera de manière incontrôlable et rapide, dépassant même le nombre maximum de connexions autorisées par le site Web source que vous avez demandé à ce moment-là. , vous devez use_pool
sur une valeur idéale (int). À ce stade, la couche inférieure utilisera Channel comme pool de connexions. Lorsque le nombre de clients créés par le pool de connexions dépasse le nombre et n'est pas suffisant, la coroutine. qui doit accéder au client sera suspendu. Et attendez que la coroutine qui utilise le client renvoie le client. Il n'y a presque aucune consommation de performances dans l'attente et le changement de coroutine, et c'est une solution très avancée .
Il convient de noter que le pool de connexions est lié服务器IP+端口
, c'est-à-dire que si vous avez plusieurs instances face au même服务器IP+端口
, le pool de connexions utilisé entre elles est également le même.
Ainsi, lorsque vous créez à plusieurs reprises une instance du服务器IP+端口
, use_pool
spécifié par l'instance nouvellement créée est autorisé à écraser la valeur précédente, c'est-à-dire que la couche inférieure du pool de connexions modifie automatiquement sa capacité lorsque la capacité augmente. La couche inférieure recréera un nouveau pool de connexions et transférera les clients. Lorsque la capacité est réduite, les clients excédentaires dans le pool de connexions seront également détruits.
En plus de ne pas oublier de configurer un pool de connexions, la méthode de gestion des exceptions doit également être conforme à vos habitudes de programmation. La gestion des exceptions par défaut de Saber
est la plus courante et la plus rigoureuse抛出异常
, mais Saber
prend également en charge l'utilisation silencieuse des错误码
et状态位
, peuvent être plus conformes aux goûts de nombreuses personnes.
SaberGM:: exceptionReport ( 0 ); // 关闭抛出异常报告, 在业务代码之前注册即可全局生效
$ saber -> exceptionReport ( 0 ); //也可以单独设置某个实例
De la même manière, la configuration souhaitée peut être préconfigurée avant le code métier, comme onWorkerStart
ou même avant le démarrage swoole_server
.
SaberGM:: default ([
' exception_report ' => 0
' use_pool ' => true
]);
Configurer ainsi les options souhaitées peut vous offrir une meilleure expérience !
go ( function (){
// your code with pool ...
saber_pool_release (); // and this script will exit
});
Si vous utilisez un pool de connexions dans un script unique, puisque le client coroutine existe dans le pool, le nombre de références est de 1 et ne peut pas être libéré, ce qui fera que swoole sera toujours dans la boucle d'événements et que le script ne pourra pas se terminer. vous devez appeler manuellement saber_pool_release
ou saber_exit
ou swoole_event_exit
pour quitter normalement, ou vous pouvez utiliser exit pour forcer la sortie du script en cours (n'utilisez pas exit sur le serveur).
Le symbole
|
sépare plusieurs valeurs facultatives
clé | taper | introduction | exemple | remarque |
---|---|---|---|---|
version_protocole | chaîne | Version du protocole HTTP | 1.1 | HTTP2 est encore en planification |
base_uri | chaîne | chemin de base | http://httpbin.org | Sera fusionné avec l'uri selon la RFC3986 |
uri | chaîne | identifiant de ressource | http://httpbin.org/get | /get get | | Les chemins absolus et relatifs peuvent être utilisés |
uri_query | chaîne|tableau | demander des informations | ['foo' => 'bar'] | Les non-chaînes sont automatiquement converties |
méthode | chaîne | Méthode de demande | get | post head delete patch put | Le calque inférieur est automatiquement converti en majuscule |
en-têtes | tableau | en-tête de demande | ['DNT' => '1'] | ['accept' => ['text/html'], ['application/xml']] | Les noms de champs ne sont pas sensibles à la casse, mais les règles de casse d'origine lors de la configuration seront conservées. Chaque valeur de champ sous-jacente sera automatiquement divisée en tableaux conformément au PSR-7. |
cookies | array | string | ['foo '=> 'bar'] | 'foo=bar; foz=baz' | La couche inférieure est automatiquement convertie en objet Cookies et son domaine est défini sur l'URI actuel, avec des attributs complets au niveau du navigateur. | |
agent utilisateur | chaîne | agent utilisateur | curl-1.0 | La valeur par défaut est Chrome sur la plateforme Macos |
référent | chaîne | Adresse source | https://www.google.com | La valeur par défaut est vide |
réorienter | int | Nombre maximum de redirections | 5 | La valeur par défaut est 3, et lorsqu'elle est 0, il n'y a pas de redirection. |
garder_en vie | bouffon | S'il faut rester connecté | true | false | La valeur par défaut est true, la connexion sera automatiquement réutilisée lors de la redirection |
type_content | chaîne | Type d'encodage du contenu envoyé | text/plain SwlibHttpContentType::JSON | La valeur par défaut est application/x-www-form-urlencoded |
données | array | string | données envoyées | 'foo=bar&dog=cat' | ['foo' => 'bar'] | Les données seront automatiquement codées en fonction du content_type |
avant | array callable | | Intercepteur de pré-demande | function(Request $request){} | Veuillez vous référer à la section Intercepteur pour plus de détails. |
après | array callable | | Intercepteur post-réponse | function(Response $response){} | Veuillez vous référer à la section Intercepteur pour plus de détails. |
avant_redirection | array callable | | Intercepteur post-redirection | function(Request $request, Response $response){} | Veuillez vous référer à la section Intercepteur pour plus de détails. |
temps mort | flotter | temps mort | 0,5 | La valeur par défaut est 5 s, prend en charge le délai d'attente en millisecondes |
adresse_de-liaison | chaîne | Lier l'adresse | 192.168.1.1 ou eth0 | Non défini par défaut |
liaison_port | int | Lier le port | 80 | Non défini par défaut |
procuration | chaîne | par intérim | http://127.0.0.1:1087 | socks5://127.0.0.1:1087 | Supporte http et chaussettes5 |
SSL | int | S'il faut activer la connexion SSL | 0=关闭 1=开启 2=自动 | Automatique par défaut |
fichier cafile | chaîne | fichier ca | __DIR__ . '/cacert.pem' | Livré par défaut |
ssl_verify_peer | bouffon | Vérifier le certificat côté serveur | false true | | Désactivé par défaut |
ssl_allow_self_signed | bouffon | Autoriser les certificats auto-signés | true | false | Autorisé par défaut |
fichier_cert_ssl | chaîne | certificat de certification | __DIR__ . '/ssl.cert' | Non défini par défaut |
fichier_clé_ssl | chaîne | clé clé privée | __DIR__ . '/ssl.key' | Non défini par défaut |
icônev | tableau | Spécifier la conversion d'encodage | ['gbk', 'utf-8'] | Il y a trois paramètres au total : from,to,use_mb , qui sont automatiquement reconnus par défaut. |
rapport_exception | int | Niveau de rapport d'exception | HttpExceptionMask :: E_ALL | Signaler toutes les exceptions par défaut |
exception_handle | appelable|tableau | Fonction de gestion personnalisée des exceptions | function(Exception $e){} | Les erreurs peuvent être ignorées lorsque la fonction renvoie vrai |
réessayer | appelable | Intercepteur de nouvelle tentative automatique | function(Request $request, Response $response){} | Après une erreur et avant de réessayer |
retry_time | int | Nouvelles tentatives automatiques | Ne pas réessayer par défaut | |
utiliser_pool | bool|int | pool de connexion | true | false |
clé_pool | appelable|tableau | Clé du pool de connexion | function(Request $request):string { return $key; } | La valeur par défaut est host:port de l'adresse demandée |
Pour plus de facilité d'utilisation et de tolérance aux pannes, les valeurs clés des éléments de configuration ont un mécanisme d'alias. Il est recommandé d'utiliser autant que possible le nom d'origine :
clé | alias |
---|---|
méthode | 0 |
uri | 1 | url |
données | 2 | body |
base_uri | base_url |
après | rappel |
type_content | content-type | contentType |
cookies | cookies |
en-têtes | en-tête |
réorienter | suivre |
agent utilisateur | ua | user-agent |
rapport_exception | error_report | report |
avant_retry | réessayer |
référent | ref referrer |
L'intercepteur est une fonctionnalité très puissante de Sabre, qui vous permet de gérer diverses choses très facilement, comme l'impression des journaux de développement :
SaberGM:: get ( ' http://twosee.cn/ ' , [
' before ' => function ( Saber Request $ request ) {
$ uri = $ request -> getUri ();
echo " log: request $ uri now... n" ;
},
' after ' => function ( Saber Response $ response ) {
if ( $ response -> success ) {
echo " log: success! n" ;
} else {
echo " log: failed n" ;
}
echo " use { $ response -> time } s " ;
}
]);
// log : request http : // twosee . cn / now...
// log : success !
// use 0 . 52036285400391s
Même les fonctions et会话
异常自定义处理函数
sont implémentées via des intercepteurs.
Il peut y avoir plusieurs intercepteurs, qui seront exécutés dans l'ordre d'enregistrement, et vous pouvez nommer l'intercepteur . Il vous suffit de l'envelopper dans un tableau et de spécifier la valeur de la clé. Si vous souhaitez supprimer cet intercepteur, écrasez-le simplement. une valeur nulle.
[
' after ' => [
' interceptor_new ' => function (){},
' interceptor_old ' => null
]
]
Les intercepteurs peuvent être enregistrés de quatre manières (4 fonctions de rappel PHP) :
callable: function (){}
string: ' function_name '
string: ' ClassName::method_name '
array: [ $ object , ' method_name ' ]
La mise en œuvre des cookies est complète au niveau du navigateur . Elle fait spécifiquement référence à la mise en œuvre du navigateur Chrome et suit ses règles pertinentes.
Les cookies sont un ensemble de cookies et chaque cookie possède les propriétés suivantes :
name
, value
, expires
, path
, session
, secure
, httponly
, hostonly
Et la classe Cookies prend en charge la conversion de plusieurs formats, tels que
foo=bar; foz=baz; apple=banana
Set-Cookie: logged_in=no; domain=.github.com; path=/; expires=Tue, 06 Apr 2038 00:00:00 -0000; secure; HttpOnly
['foo'=>'bar', 'foz'=>'baz']
Attendez que le format soit transféré vers la classe Cookie ou que la classe Cookie soit sérialisée dans ces formats.
Les cookies prennent également en charge la vérification du nom de domaine et de la limite de temps sans perdre aucune information. Par exemple, si le domaine est github.com
, le cookie n'apparaîtra pas dans help.github.com
sauf si le domaine n'est pas hôte uniquement (caractère générique .github.com
).
S'il s'agit d'un cookie de session (il n'a pas de délai d'expiration et expire à la fermeture du navigateur), l'attribut expires sera défini sur l'heure actuelle et vous pourrez définir une heure spécifique via l'intercepteur .
En lisant l'attribut brut des cookies, il peut être facilement conservé dans la base de données , ce qui est très approprié pour les applications d'exploration de connexion.
Pour plus de détails, veuillez vous référer à la documentation et aux exemples de la bibliothèque Swlib/Http.
Saber suit la règle de séparation des affaires des erreurs . Lorsqu'une partie de la demande échoue, une exception est levée par défaut .
Ce qui est puissant, c'est que la gestion des exceptions de Sabre est également diversifiée et aussi complète que la gestion native des exceptions de PHP.
L'espace de noms d'exception se trouve dans SwlibHttpException
Exception | Introduction | scène |
---|---|---|
DemandeException | La demande a échoué | Erreur de configuration de la demande |
ConnectException | La connexion a échoué | S'il n'y a pas de connexion réseau, si la requête DNS échoue, si le délai expire, etc., la valeur de errno est égale à Linux errno. Vous pouvez utiliser swoole_strerror pour convertir les codes d'erreur en messages d'erreur. |
TooManyRedirectsException | Nombre de redirections dépassé | Le nombre de redirections dépasse la limite définie et l'exception levée imprimera les informations de suivi des redirections. |
ClientException | Exception client | Le serveur a renvoyé un code d'erreur 4xx |
ServeurException | Exception du serveur | Le serveur a renvoyé un code d'erreur 5xx |
BadResponseException | Échec de l'obtention de la réponse inconnue | Le serveur n'a pas répondu ou a renvoyé un code d'erreur non reconnu. |
En plus des méthodes d'exception générales, toutes les classes d'exception HTTP disposent également des méthodes suivantes :
Méthode | Introduction |
---|---|
obtenirRequête | Obtenir une instance de requête |
aRéponse | S'il faut obtenir une réponse |
obtenirRéponse | Obtenir une instance de réponse |
getResponseBodySummary | Obtenez le contenu récapitulatif du corps de la réponse |
try {
echo SaberGM:: get ( ' http://httpbin.org/redirect/10 ' );
} catch ( TooManyRedirectsException $ e ) {
var_dump ( $ e -> getCode ());
var_dump ( $ e -> getMessage ());
var_dump ( $ e -> hasResponse ());
echo $ e -> getRedirectsTrace ();
}
// int ( 302)
// string ( 28) "Too many redirects occurred ! "
// bool ( true )
#0 http : // httpbin . org / redirect/10
#1 http : // httpbin . org / relative - redirect/9
#2 http : // httpbin . org / relative - redirect/8
Dans le même temps, Sabre prend également en charge la gestion des exceptions de manière douce, afin d'éviter que les utilisateurs ne paniquent dans des environnements réseau instables et n'aient à envelopper le code avec try à chaque étape :
Définissez le niveau errorReport, qui est globalement efficace et ne prendra pas effet sur les instances créées .
// 启用所有异常但忽略重定向次数过多异常
SaberGM:: exceptionReport (
HttpExceptionMask:: E_ALL ^ HttpExceptionMask:: E_REDIRECT
);
Les valeurs suivantes (numériques ou symboliques) sont utilisées pour créer un masque de bits qui spécifie le message d'erreur à signaler. Vous pouvez utiliser des opérateurs au niveau du bit pour combiner ces valeurs ou pour masquer certains types d'erreurs. Drapeaux et masques
Masque | Valeur | Introduction |
---|---|---|
E_NONE | 0 | ignorer toutes les exceptions |
E_REQUEST | 1 | Correspond à RequestException |
E_CONNECT | 2 | Correspond à RequestException |
E_REDIRECT | 4 | Correspond à RequestException |
E_BAD_RESPONSE | 8 | Correspond à BadRException |
E_CLIENT | 16 | Correspond à ClientException |
E_SERVEUR | 32 | Correspond à ServerException |
E_TOUS | 63 | Toutes les exceptions |
Cette fonction peut gérer les erreurs générées dans les requêtes HTTP à votre manière et vous pouvez définir plus librement les exceptions que vous souhaitez intercepter/ignorer.
Remarque : À moins que la fonction ne renvoie VRAI (ou une autre valeur vraie), l'exception continuera à être levée au lieu d'être interceptée par la fonction personnalisée.
SaberGM:: exceptionHandle ( function ( Exception $ e ) {
echo get_class ( $ e ) . " is caught! " ;
return true ;
});
SaberGM:: get ( ' http://httpbin.org/redirect/10 ' );
//output : Swlib Http E xceptionTooManyRedirectsException is caught !
Téléchargement de fichiers | WebSockets | Analyseur automatique | Réessai automatique | Téléchargement de BigFile | Cache | Pool de clients | AléatoireUA |
---|---|---|---|---|---|---|---|
4 (haute priorité) | 3 | 2 | 1 | .5 | .5 | .5 | .175 |
Le principal avantage de HTTP/2 est qu'il permet de multiplexer de nombreuses requêtes au sein d'une seule connexion, supprimant ainsi [presque] la limite du nombre de requêtes simultanées - et une telle limite n'existe pas lorsque vous parlez à vos propres backends. s'aggrave lors de l'utilisation de HTTP/2 sur les backends, en raison de l'utilisation d'une seule connexion TCP au lieu de plusieurs, donc Http2 ne sera pas une priorité (#ref).
Ajoutez les fichiers sources de ce projet au Include Path
de l'EDI.
(S'il est installé à l'aide de Composer, vous pouvez inclure l'intégralité du dossier du fournisseur et PHPStorm l'inclura automatiquement)
Une bonne rédaction de commentaires permet à Saber de prendre parfaitement en charge les invites automatiques de l'IDE. Il suffit d'écrire le symbole de flèche après l'objet pour afficher tous les noms de méthodes d'objet. Les noms sont très faciles à comprendre. Un grand nombre de méthodes suivent la spécification PSR ou sont implémentées en se référant à la spécification PSR. Projet Guzzle (merci) .
Pour les invites IDE sur les classes sous-jacentes liées à Swoole, vous devez introduire le swoole-ide-helper d'eaglewu (le compositeur sera installé par défaut dans l'environnement de développement. Cependant, ce projet est maintenu manuellement et n'est pas terminé. Vous pouvez également utiliser swoft). -ide-helper ou :
L'assistant d'idées officiel de Swoole.
Bienvenue pour soumettre des problèmes et des relations publiques.
Étant donné que les coroutines (__call, __callStatic) ne peuvent pas être utilisées dans les méthodes magiques, les méthodes dans le code source sont définies manuellement.
Pour faciliter l'utilisation, des alias ont été fournis pour toutes les méthodes de requête prises en charge.
public static function psr( array $ options = []): Swlib Saber Request
public static function wait(): Swlib Saber
public static function request( array $ options = [])
public static function get (string $ uri , array $ options = [])
public static function delete (string $ uri , array $ options = [])
public static function head (string $ uri , array $ options = [])
public static function options (string $ uri , array $ options = [])
public static function post (string $ uri , $ data = null , array $ options = [])
public static function put (string $ uri , $ data = null , array $ options = [])
public static function patch (string $ uri , $ data = null , array $ options = [])
public static function download (string $ uri , string $ dir , int $ offset , array $ options = [])
public static function requests (array $ requests , array $ default_options = []): Swlib Saber ResponseMap
public static function list(array $ options , array $ default_options = []): Swlib Saber ResponseMap
public static function websocket (string $ uri )
public static function default (?array $ options = null ): array
public static function exceptionReport (?int $ level = null ): int
public static function exceptionHandle (callable $ handle ): void
public static function create( array $ options = []): self
public static function session( array $ options = []): self
public static function websocket( string $ uri ): WebSocket
public function request( array $ options )
public function get( string $ uri , array $ options = [])
public function delete( string $ uri , array $ options = [])
public function head( string $ uri , array $ options = [])
public function options( string $ uri , array $ options = [])
public function post( string $ uri , $ data = null , array $ options = [])
public function put( string $ uri , $ data = null , array $ options = [])
public function patch( string $ uri , $ data = null , array $ options = [])
public function download( string $ uri , string $ dir , int $ offset , array $ options = [])
public function requests( array $ requests , array $ default_options = []): ResponseMap
public function list( array $ options , array $ default_options = []): ResponseMap
public function upgrade(? string $ path = null ): WebSocket
public function psr( array $ options = []): Request
public function wait(): self
public function exceptionReport(? int $ level = null ): int
public function exceptionHandle( callable $ handle ): void
public static function getAliasMap(): array
public function setOptions( array $ options = [], ? Swlib Saber Request $ request = null ): self
public static function getDefaultOptions(): array
public static function setDefaultOptions( array $ options = [])
public function getExceptionReport(): int
public function setExceptionReport( int $ level ): self
public function isWaiting(): bool
public function getPool()
public function withPool( $ bool_or_max_size ): self
public function tryToRevertClientToPool( bool $ connect_failed = false )
public function getSSL(): int
public function withSSL( int $ mode = 2 ): self
public function getCAFile(): string
public function withCAFile( string $ ca_file = __DIR__ . ' /cacert.pem ' ): self
public function getSSLCertFile(): string
public function withSSLCertFile( string $ cert_file ): self
public function getSSLKeyFile(): string
public function withSSLKeyFile( string $ key_file ): self
public function withSSLVerifyPeer( bool $ verify_peer = false , ? string $ ssl_host_name = '' ): self
public function withSSLAllowSelfSigned( bool $ allow = true ): self
public function getSSLConf()
public function getKeepAlive()
public function withKeepAlive( bool $ enable ): self
public function withBasicAuth(? string $ username = null , ? string $ password = null ): self
public function withXHR( bool $ enable = true )
public function getProxy(): array
public function withProxy( string $ host , int $ port ): self
public function withSocks5( string $ host , int $ port , ? string $ username , ? string $ password ): self
public function withoutProxy(): self
public function getBindAddress(): ? string
public function withBindAddress( string $ address ): self
public function getBindPort(): ? int
public function withBindPort( int $ port ): self
public function getTimeout(): float
public function withTimeout( float $ timeout ): self
public function getRedirect(): int
public function getName()
public function withName( $ name ): self
public function withRedirect( int $ time ): self
public function isInQueue(): bool
public function withInQueue( bool $ enable ): self
public function getRetryTime(): int
public function withRetryTime( int $ time ): self
public function withAutoIconv( bool $ enable ): self
public function withExpectCharset( string $ source = ' auto ' , string $ target = ' utf-8 ' , bool $ use_mb = false ): self
public function withDownloadDir( string $ dir ): self
public function withDownloadOffset( int $ offset ): self
public function resetClient( $ client )
public function exec()
public function recv()
public function getRequestTarget(): string
public function withRequestTarget( $ requestTarget ): self
public function getMethod(): string
public function withMethod( $ method ): self
public function getUri(): Psr Http Message UriInterface
public function withUri(? Psr Http Message UriInterface $ uri , $ preserveHost = false ): self
public function getCookieParams(): array
public function getCookieParam( string $ name ): string
public function withCookieParam( string $ name , ? string $ value ): self
public function withCookieParams( array $ cookies ): self
public function getQueryParam( string $ name ): string
public function getQueryParams(): array
public function withQueryParam( string $ name , ? string $ value ): self
public function withQueryParams( array $ query ): self
public function getParsedBody(? string $ name = null )
public function withParsedBody( $ data ): self
public function getUploadedFile( string $ name ): Psr Http Message UploadedFileInterface
public function getUploadedFiles(): array
public function withUploadedFile( string $ name , ? Psr Http Message UploadedFileInterface $ uploadedFile ): self
public function withoutUploadedFile( string $ name ): self
public function withUploadedFiles( array $ uploadedFiles ): self
public function __toString()
public function getProtocolVersion(): string
public function withProtocolVersion( $ version ): self
public function hasHeader( $ name ): bool
public function getHeader( $ name ): array
public function getHeaderLine( $ name ): string
public function getHeaders( bool $ implode = false , bool $ ucwords = false ): array
public function getHeadersString( bool $ ucwords = true ): string
public function withHeader( $ raw_name , $ value ): self
public function withHeaders( array $ headers ): self
public function withAddedHeaders( array $ headers ): self
public function withAddedHeader( $ raw_name , $ value ): self
public function withoutHeader( $ name ): self
public function getBody(): Psr Http Message StreamInterface
public function withBody(? Psr Http Message StreamInterface $ body ): self
public function getCookies()
public function setCookie( array $ options ): self
public function unsetCookie( string $ name , string $ path = '' , string $ domain = '' ): self
public function withInterceptor( string $ name , array $ interceptor )
public function withAddedInterceptor( string $ name , array $ functions ): self
public function withoutInterceptor( string $ name ): self
public function callInterceptor( string $ name , $ arguments )
public function getSpecialMark( string $ name = ' default ' )
public function withSpecialMark( $ mark , string $ name = ' default ' ): self
public function isSuccess(): bool
public function getUri(): Psr Http Message UriInterface
public function getTime(): float
public function getRedirectHeaders(): array
public function getStatusCode()
public function withStatus( $ code , $ reasonPhrase = '' )
public function getReasonPhrase()
public function __toString()
public function getProtocolVersion(): string
public function withProtocolVersion( $ version ): self
public function hasHeader( $ name ): bool
public function getHeader( $ name ): array
public function getHeaderLine( $ name ): string
public function getHeaders( bool $ implode = false , bool $ ucwords = false ): array
public function getHeadersString( bool $ ucwords = true ): string
public function withHeader( $ raw_name , $ value ): self
public function withHeaders( array $ headers ): self
public function withAddedHeaders( array $ headers ): self
public function withAddedHeader( $ raw_name , $ value ): self
public function withoutHeader( $ name ): self
public function getBody(): Psr Http Message StreamInterface
public function withBody(? Psr Http Message StreamInterface $ body ): self
public function getCookies()
public function setCookie( array $ options ): self
public function unsetCookie( string $ name , string $ path = '' , string $ domain = '' ): self
public function getSpecialMark( string $ name = ' default ' )
public function withSpecialMark( $ mark , string $ name = ' default ' ): self
public function getParsedJsonArray( bool $ reParse = false ): array
public function getParsedJsonObject( bool $ reParse = false ): object
public function getParsedQueryArray( bool $ reParse = false ): array
public function getParsedXmlArray( bool $ reParse = false ): array
public function getParsedXmlObject( bool $ reParse = false ): SimpleXMLElement
public function getParsedDomObject( bool $ reParse = false ): DOMDocument
public function getDataRegexMatch( string $ regex , $ group = null , int $ fill_size )
public function getDataRegexMatches( string $ regex , int $ flag ): array
public function isExistInData( string $ needle , int $ offset )
public function enqueue( $ request )
public function getMaxConcurrency(): int
public function withMaxConcurrency( int $ num = - 1 ): self
public function recv(): Swlib Saber ResponseMap
public function withInterceptor( string $ name , array $ interceptor )
public function withAddedInterceptor( string $ name , array $ functions ): self
public function withoutInterceptor( string $ name ): self
public function callInterceptor( string $ name , $ arguments )
public $ time = 0.0 ;
public $ status_map = [];
public $ success_map = [];
public $ success_num = 0 ;
public $ error_num = 0 ;
public function offsetSet( $ index , $ response )
public function __toString()
public function withMock( bool $ ssl ): self
public function recv( float $ timeout = - 1 )
public function push( string $ data , int $ opcode = 1 , bool $ finish = true ): bool
public function close(): bool
public $ finish = true ;
public $ opcode = null ;
public $ data = null ;
public function getOpcodeDefinition()
public function getOpcode()
public function getData()
public function __toString()