Download the PHP package dybee/saber without Composer
On this page you can find all versions of the php package dybee/saber. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Informations about the package saber
Saber
简介
HTTP军刀(呆毛王), Swoole人性化组件库
之PHP高性能HTTP客户端, 基于Swoole原生协程, 支持多种风格操作, 底层提供高性能解决方案, 让开发者专注于功能开发, 从传统同步阻塞且配置繁琐的Curl中解放.
English Document
- 基于Swoole协程Client开发
- 人性化使用风格, ajax.js/axios.js/requests.py用户福音, 同时支持PSR风格操作
- 浏览器级别完备的Cookie管理机制, 完美适配爬虫/API代理应用
- 请求/响应/异常拦截器
- 多请求并发, 并发重定向优化
- 连接池, 自动化复用长连接
- 通道池(Chan): 最大连接数限制+无阻塞
- HTTPS连接, CA证书自动化支持
- HTTP/Socks5 Proxy支持
- WebSocket连接支持
- 毫秒级超时定时器
- 自动化 编码请求/解析响应 数据
- 响应报文自动编码转换
- 异步超大文件上传/下载, 断点重传
- 自动重试机制
- 单次并发数控制
- 多模式/超细粒度异常处理机制
- (=)浏览器级别缓存机制
- (=)随机UA生成器
安装
最好的安装方法是通过 Composer 包管理器 :
依赖
- PHP71 or later
- Swoole 2.1.2 or later
- Swoole 4 is the best
协程调度
Swoole底层实现协程调度, 业务层无需感知, 开发者可以无感知的用同步的代码编写方式达到异步IO的效果和超高性能,避免了传统异步回调所带来的离散的代码逻辑和陷入多层回调中导致代码无法维护.
需要在onRequet
, onReceive
, onConnect
等事件回调函数中使用, 或是使用go关键字包裹 (swoole.use_shortname
默认开启).
目录
- 例子
- 静态方法
- 生成实例
- 生成会话
- 并发请求
- 数据解析
- 网络代理
- 文件上传
- 超大文件下载
- 自动重试
- 缓存机制
- PSR风格
- WebSocket
- 极限压力测试
- 列式请求集
- 单次并发控制
- 高性能无极限协程连接池
- 无限连接池
- 定容连接池
- 动态变容
- 注意事项
- 注册你所希望的配置
- 注意在一次性脚本中释放连接池
- 注册你所希望的配置
- 配置参数表
- 配置参数别名
- 拦截器
- Cookies
- 属性
- 任意格式互转
- 域名路径和过期时限校验
- 持久化存储
- 异常机制
- 捕获例子
- 异常报告级别控制
- 掩码表
- 异常自定义处理函数
- 捕获例子
- Road Map
- Why not Http2 ?
- IDE Helper
- 重中之重
- 附录
- Saber API
- Swlib\SaberGM
- Swlib\Saber
- Swlib\Saber\Request
- Swlib\Saber\Response
- Swlib\Saber\RequestQueue
- Swlib\Saber\ResponseMap
- Swlib\Saber\WebSocket
- Swlib\Saber\WebSocketFrame
- Saber API
例子
静态方法
数据自动打包: 传入的data会自动转换成content-type所指定的类型格式
默认为
x-www-form-urlencoded
, 也支持json
等其它格式
SaberGM
:= Saber Global Manager
, 如果觉得类名有点长, 可以使用class_alias
自己取别名, 推荐服务中使用生成实例的方式使用, 而把SaberGM
作为快捷方式.
生成实例
适用API代理服务
生成会话
Session会自动保存cookie信息, 其实现是浏览器级别完备的
并发请求
注意: 此处使用了并发重定向优化方案, 多个重定向总是依旧并发的而不会退化为队列的单个请求
数据解析
目前支持json
,xml
,html
,url-query
四种格式的数据快速解析
网络代理
支持HTTP和SOCKS5代理
文件上传
底层自动协程调度, 可支持异步发送超大文件, 断点续传
同时上传三个文件(三种参数风格
string
|array
|object
)
超大文件下载
Download收到数据后会直接异步写入到磁盘, 而不是在内存中对HttpBody进行拼接. 因此download仅使用小量内存, 就可以完成超大文件的下载. 且支持断点续传, 通过设置offset参数来进行断点下载.
异步下载Saber壁纸
自动重试
在爬虫项目中, 请求失败自动重试是非常常见的需求, 比如会话过期后重新登录.
而Saber
内置了此功能, 并可使用拦截器
来强化它.
如未设置retry_time
而设置了retry
拦截器, 则retry_time
会置为1, 如retry
拦截器的回调方法返回了false
, 无论retry_time
是多少, 都会在返回false
时终止重试.
缓存机制
有时候HTTP资源并不会总是变更, 我们可以学习浏览器缓存不会变动的资源, 来加快请求效率, 由Saber
自动化地完成且不必自己维护缓存逻辑(CURD或文件读写), 协程的调度使得其不论如何都不会阻塞服务器, Saber
没有使用中间件机制因为它和Swoole是强相关的, 但是缓存可以使用 内存/文件/数据库
等多种方式, 所以虽然它尚未实现, 但它将会列入Saber
的后续路线图中.
PSR风格
WebSocket
可以通过websocketFrame数据帧的__toString方法直接打印返回数据字符串
极限压力测试
测试机器为最低配MacBookPro, 请求服务器为本地echo服务器
0.9秒完成6666个请求, 成功率100%.
列式请求集
在实际项目中, 经常会存在使用URL列表来配置请求的情况, 因此提供了list方法来方便使用:
单次并发控制
在实际爬虫项目中, 我们往往要限制单次并发请求数量以防被服务器防火墙屏蔽, 而一个max_co
参数就可以轻松地解决这个问题, max_co
会将请求根据上限量分批将请求压入队列并执行收包.
高性能无极限协程连接池
在常驻内存的服务器中使用时, 一定要手动开启连接池选项:
在通过该实例使用时, 就会启用连接池特性, 即底层与www.swoole.com
网站的连接客户端将会用一个全局连接池存取, 避免了每次使用创建/连接的开销.
无限连接池
在参数为true
时, 该网站的连接池容量是无限的, 一般情况下没有问题, 且无限容量的连接池性能更好.
定容连接池
但如果你使用其作为爬虫代理服务, 遭遇大量请求时, 连接池中的客户端数量就会不可控制地快速上升, 甚至超出你所请求的源网站的最大允许连接数, 这时候你就需要将use_pool
设置为一个理想数值(int), 此时, 底层会使用Channel作为连接池, 在连接池创建的客户端超出数量且不够取用时, 挂起需要取用客户端的协程, 并等待正在使用客户端的协程归还客户端, 协程等待和切换几乎没有多大的性能消耗, 是一种非常先进的解决方式.
动态变容
需要注意的是, 连接池是绑定服务器IP+端口
的, 即如果你有多个实例面向的是同一个服务器IP+端口
, 他们之间使用的连接池也是同一个.
所以你在重复创建服务器IP+端口
的实例时, 新创建的实例指定的use_pool
是允许覆盖之前数值的, 即连接池底层是自动变容的, 容量增加时底层会重新创建新的连接池并转移客户端, 容量减少时也会销毁在连接池内的多余的客户端.
注意事项
注册你所希望的配置
除了一定要记得配备连接池以外, 异常处理的方式也需要注意是符合你的编程习惯的, Saber
默认的异常处理是最主流且严谨的抛出异常
, 但Saber
也支持静默地使用错误码
和状态位
, 可能更符合很多人的口味.
同理, 你所希望的配置都可以在业务代码之前如onWorkerStart
甚至是swoole_server
启动之前预先配置.
像这样配置你所期望的选项可以让你获得更好的使用体验!
注意在一次性脚本中释放连接池
如果你在一次性脚本中使用的连接池, 由于协程客户端是存在池中的, 引用计数为1无法释放, 就会导致swoole一直处于事件循环中, 脚本就无法退出, 你需要手动调用saber_pool_release
或saber_exit
或swoole_event_exit
来正常退出, 也可以使用exit强制退出当前脚本(不要在server中使用exit).
配置参数表
|
符号分割多种可选值
key | type | introduction | example | remark |
---|---|---|---|---|
protocol_version | string | HTTP协议版本 | 1.1 | HTTP2还在规划中 |
base_uri | string | 基础路径 | http://httpbin.org |
将会与uri按照rfc3986合并 |
uri | string | 资源标识符 | http://httpbin.org/get | /get | get |
可以使用绝对路径和相对路径 |
uri_query | string|array | 请求信息 | ['foo' => 'bar'] |
非字符串会自动转换 |
method | string | 请求方法 | get | post | head | patch | put | delete |
底层自动转换为大写 |
headers | array | 请求报头 | ['DNT' => '1'] | ['accept' => ['text/html'], ['application/xml']] |
字段名不区分大小写, 但会保留设定时的原始大小写规则, 底层每个字段值会根据PSR-7自动分割为数组 |
cookies | array |string |
['foo '=> 'bar'] | 'foo=bar; foz=baz' |
底层自动转化为Cookies对象, 并设置其domain为当前的uri, 具有浏览器级别的完备属性. | |
useragent | string | 用户代理 | curl-1.0 |
默认为macos平台的chrome |
referer | string | 来源地址 | https://www.google.com |
默认为空 |
redirect | int | 最大重定向次数 | 5 | 默认为3, 为0时不重定向. |
keep_alive | bool | 是否保持连接 | true | false |
默认为true, 重定向时会自动复用连接 |
content_type | string | 发送的内容编码类型 | text/plain | Swlib\Http\ContentType::JSON |
默认为application/x-www-form-urlencoded |
data | array | string |
发送的数据 | 'foo=bar&dog=cat' |['foo' => 'bar'] |
会根据content_type自动编码数据 |
before | callable | array |
请求前拦截器 | function(Request $request){} |
具体参考拦截器一节 |
after | callable | array |
响应后拦截器 | function(Response $response){} |
具体参考拦截器一节 |
before_redirect | callable | array |
重定向后拦截器 | function(Request $request, Response $response){} |
具体参考拦截器一节 |
timeout | float | 超时时间 | 0.5 | 默认5s, 支持毫秒级超时 |
bind_address | string | 绑定地址 | 192.168.1.1 或 eth0 | 默认不设置 |
bind_port | int | 绑定端口 | 80 | 默认不设置 |
proxy | string | 代理 | http://127.0.0.1:1087 | socks5://127.0.0.1:1087 |
支持http和socks5 |
ssl | int | 是否开启ssl连接 | 0=关闭 1=开启 2=自动 |
默认自动 |
cafile | string | ca文件 | __DIR__ . '/cacert.pem' |
默认自带 |
ssl_verify_peer | bool | 验证服务器端证书 | false | true |
默认关闭 |
ssl_allow_self_signed | bool | 允许自签名证书 | true | false |
默认允许 |
ssl_cert_file | string | cert 证书 | __DIR__ . '/ssl.cert' |
默认不设置 |
ssl_key_file | string | key 私钥 | __DIR__ . '/ssl.key' |
默认不设置 |
iconv | array | 指定编码转换 | ['gbk', 'utf-8'] |
共三个参数为from,to,use_mb , 默认自动识别 |
exception_report | int | 异常报告级别 | HttpExceptionMask::E_ALL | 默认汇报所有异常 |
exception_handle | callable|array | 异常自定义处理函数 | function(Exception $e){} |
函数返回true时可忽略错误 |
retry | callable | 自动重试拦截器 | function(Request $request, Response $response){} |
位于发生错误后及重试之前 |
retry_time | int | 自动重试次数 | 默认不重试 | |
use_pool | bool|int | 连接池 | true |
false |
pool_key | callable|array | 连接池的key | function(Request $request):string { return $key; } |
默认为请求地址的host:port |
配置参数别名
为了使用方便与容错, 配置项的键值具有别名机制, 建议尽量使用本名:
key | alias |
---|---|
method | 0 |
uri | 1 | url |
data | 2 | body |
base_uri | base_url |
after | callback |
content_type | content-type | contentType |
cookies | cookie |
headers | header |
redirect | follow |
useragent | ua | user-agent |
exception_report | error_report | report |
before_retry | retry |
referer | ref | referrer |
拦截器
拦截器是Saber的一个非常强大的特性, 它可以让你非常方便地处理各种事情, 比如打印dev日志:
甚至连异常自定义处理函数
,会话
都是通过拦截器来实现的.
拦截器可以有多个, 会依照注册顺序执行, 并且你可以为拦截器命名, 只需要使用数组包裹并指定key值, 如果你要删除这个拦截器, 给它覆盖一个null值即可.
拦截器可以使用四种方式注册(4种PHP回调函数):
Cookies
Cookie的实现是浏览器级别完备的, 它具体参考了Chrome浏览器的实现, 并遵循其相关规则.
属性
Cookies是一堆Cookie的集合, 而每个Cookie具有以下属性:
name
, value
, expires
, path
, session
, secure
, httponly
, hostonly
任意格式互转
并且Cookies类支持多种格式互转, 如
-
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']
等格式转到Cookie类, 或是Cookie类到该几种格式的序列化.
域名路径和过期时限校验
Cookie也支持域名和时限校验, 不会丢失任何信息, 如domain是github.com
cookie, 不会出现在help.github.com
, 除非domain不是hostonly的(.github.com
通配).
如果是session-cookie(没有过期时间,浏览器关闭则过期的), expires属性会设置为当前时间, 你可以通过拦截器来对其设置具体的时间.
持久化存储
通过读取Cookies的raw属性, 可以轻松地将其持久化到数据库中, 非常适合登录类爬虫应用.
更多详情具体请参考Swlib/Http库文档和例子.
异常机制
Saber遵循将业务与错误分离的守则, 当请求任意环节失败时, 默认都将会抛出异常.
强大的是, Saber的异常处理也是多样化的, 且和PHP的原生的异常处理一样完善.
异常的命名空间位于Swlib\Http\Exception
Exception | Intro | scene |
---|---|---|
RequestException | 请求失败 | 请求配置错误 |
ConnectException | 连接失败 | 如无网络连接, DNS查询失败, 超时等, errno的值等于Linux errno。可使用swoole_strerror将错误码转为错误信息。 |
TooManyRedirectsException | 重定向次数超限 | 重定向的次数超过了设定的限制, 抛出的异常将会打印重定向追踪信息 |
ClientException | 客户端异常 | 服务器返回了4xx错误码 |
ServerException | 服务器异常 | 服务器返回了5xx错误码 |
BadResponseException | 未知的获取响应失败 | 服务器无响应或返回了无法识别的错误码 |
除一般异常方法外, 所有HTTP异常类还拥有以下方法 :
Method | Intro |
---|---|
getRequest | 获取请求实例 |
hasResponse | 是否获得响应 |
getResponse | 获取响应实例 |
getResponseBodySummary | 获取响应主体的摘要内容 |
捕获例子
异常报告级别控制
同时, Saber亦支持以温和的方式来对待异常, 以免使用者陷入在不稳定的网络环境下, 必须在每一步都使用try包裹代码的恐慌中:
设定errorReport级别, 它是全局生效的, 对已创建的实例不会生效.
掩码表
下面的值(数值或者符号)用于建立一个二进制位掩码,来制定要报告的错误信息。可以使用按位运算符来组合这些值或者屏蔽某些类型的错误。标志位与掩码
Mask | Value | Intro |
---|---|---|
E_NONE | 0 | 忽略所有异常 |
E_REQUEST | 1 | 对应RequestException |
E_CONNECT | 2 | 对应RequestException |
E_REDIRECT | 4 | 对应RequestException |
E_BAD_RESPONSE | 8 | 对应BadRException |
E_CLIENT | 16 | 对应ClientException |
E_SERVER | 32 | 对应ServerException |
E_ALL | 63 | 所有异常 |
异常自定义处理函数
本函数可以用你自己定义的方式来处理HTTP请求中产生的错误, 可以更加随心所欲地定义你想要捕获/忽略的异常.
注意: 除非函数返回 TRUE (或其它真值),否则异常会继续抛出而不是被自定义函数捕获.
Road Map
File Upload ✔ | WebSocket ✔ | AutoParser✔ | AutoRetry✔ | BigFile Download✔ | Cache | ClientPool | Random UA |
---|---|---|---|---|---|---|---|
4 (High-priority) | 3 | 2 | 1 | .5 | .5 | .5 | .175 |
Why not Http2 ?
As the main HTTP/2 benefit is that it allows multiplexing many requests within a single connection, thus [almost] removing the limit on number of simultaneous requests - and there is no such limit when talking to your own backends. Moreover, things may even become worse when using HTTP/2 to backends, due to single TCP connection being used instead of multiple ones, so Http2 Will not be a priority. (#ref)
IDE Helper
将本项目源文件加入到IDE的 Include Path
中.
(使用composer安装,则可以包含整个vendor文件夹, PHPStorm会自动包含)
良好的注释书写使得Saber完美支持IDE自动提示, 只要在对象后书写箭头符号即可查看所有对象方法名称, 名称都十分通俗易懂, 大量方法都遵循PSR规范或是参考Guzzle项目(感谢)而实现.
对于底层Swoole相关类的IDE提示则需要引入eaglewu的swoole-ide-helper(composer在dev环境下会默认安装), 但是该项目为手动维护, 不太完整, 也可以使用swoft-ide-helper或:
Swoole官方的ide-helper.
重中之重
欢迎提交issue和PR.
附录
Saber API
由于无法在魔术方法中使用协程(__call, __callStatic), 源码中的方法都是手动定义.
为了使用方便,已为所有支持的请求方法提供了别名。