- 后端
- 电商
- 前端
【免费下载链接】CRMEB
🔥CRMEB开源商城免费开源多语言商城系统,Tp6框架商城,系统可商用;包含小程序商城、H5商城、公众号商城、PC商城、App,支持分销、拼团、砍价、秒杀、优惠券、积分、会员等级、小程序直播、页面DIY,前后端分离,方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程,欢迎大家提出宝贵意见和建议
本文以 CRMEB 仓库内
crmeb/vendor/guzzle/guzzle/CHANGELOG.md为骨架,完整梳理 Guzzle 3.x(3.0.0 → 3.9.3)的演进脉络与关键修复,并结合仓库中的composer.json、composer.lock及腾讯云 COS SDK、上传模块源码,讲清这套"老牌 HTTP 客户端"为何仍存在于一个 ThinkPHP 6 商城系统中、它解决了哪些问题,以及二开时如何正确看待与使用它。
一、为什么 CRMEB 里还躺着一份 Guzzle 3?
初看crmeb/composer.json,直接依赖的 HTTP 客户端是guzzlehttp/guzzle: 6.5.5(新版命名空间GuzzleHttp\);但打开crmeb/composer.lock会发现guzzle/guzzle的v3.9.3同样被锁定安装,这正是本文关联文档crmeb/vendor/guzzle/guzzle/CHANGELOG.md所记录的那一代版本(3.x,旧命名空间Guzzle\)。
Guzzle 3 并不是被 CRMEB 直接引用的,而是作为腾讯云对象存储 SDK 的传递依赖进入项目的。证据在crmeb/composer.lock中:
"name": "qcloud/cos-sdk-v5", "require": { "guzzle/guzzle": "~3.7", "php": ">=5.3.0" }而qcloud/cos-sdk-v5/composer.json同样声明"guzzle/guzzle": "~3.7"。也就是说:CRMEB 走 COS SDK 上传到腾讯云时,实际在底层驱动 HTTP 请求的,是 Guzzle 3.9.3 这套旧实现。guzzlehttp/guzzle6.5.5 则服务其他基于 PSR-7 的请求场景。两代 Guzzle 并行存在于 vendor 目录,是本次二开需要特别注意的"双命名空间"现实。
二、3.9.x:最后一个稳定系列的收尾工作
CHANGELOG 记录的最后一个发布分支是 3.9.x,集中在 2014 年 4 月至 2015 年 3 月,多为请求序列化与流处理的边界修复。
3.9.3(2015-03-18)—— 收尾补丁
- Content-Length 不被剥离:当请求的
Content-Length显式为0时,不再被移除。对应 Client.php 中基于request.options装配请求选项的机制,显式头部应原样下发。 - 流包装器异常信息增强:
Guzzle\Stream相关包装器抛出的异常携带更多上下文,便于排查读取失败。 - 消息解析器对畸形消息不再告警:HTTP 报文解析(
Guzzle\Parser\Message)遇到不完整/畸形响应时静默处理,避免 PHP warning 干扰业务日志。 - max-age 为 0 时给出有效缓存 TTL:修正
CachePlugin在响应头Cache-Control: max-age=0场景下 TTL 计算的边界。
3.9.2(2014-09-10)
- 重试 "Connection died" 类 curl 错误:
BackoffPlugin对连接中断错误(curl 侧"连接死亡,重试新连接")增加自动重试。 - 从 phar 自动提取 cacert:以 phar 方式运行 Guzzle 时,客户端构造阶段自动解包内置 CA 证书包,替代原先每次使用都做 MD5 校验的做法。
- OPTIONS 请求支持 EntityBody:
EntityEnclosingRequest体系正式接纳 OPTIONS 方法携带实体体。
3.9.1(2014-05-07)
- 修复
ReadLimitEntityBody的无限循环问题(读取达到限制后仍可能空转)。 - 修复流校验函数:首次
read()返回假值时,仍继续消费流直到 EOF,避免过早退出导致校验不完整。
3.9.0(2014-04-23)—— 一批协议细节修正
null、false、"_guzzle_blank_"在查询串中统一序列化为空值且不带尾随=。"0"现在可以作为 URL 路径段参与拼接(此前会被当作空值吞掉)。- 空值 Cookie 会被删除;Cookie 路径匹配改为遵循RFC 6265 §5.1.4。
If-Modified-Since不再被CachePlugin无条件附加。- 服务描述更新后自动并入 service client 的 composite factory。
MockPlugin队列为空时抛出异常,避免静默吞掉测试失配。- 正确解析"以 http 开头但并非绝对 URL"的地址。
- 新增
curl_multi_select超时配置能力,支持定制并发选择的等待时长。 - OAuth 参数按字典序(字节值)排序后参与签名;
ErrorResponsePlugin修复了对越界 PHP 特性的误用。
三、3.8.x:查询串解析与缓存再验证的大修
3.8.1(2014-01-28)
- 303 重定向一律改用 GET。
setSslVerification(false)时CURLOPT_SSL_VERIFYHOST被正确置为 false(此前Guzzle\Http\ClientInterface的实现存在遗漏)。RedirectPlugin遵循RFC 3986严格规则合并基础 URL 与相对 URL。- 请求体允许被设为字符串
"0"。 - PHP 流方式发请求不再强制
HTTP/1.0。 ExceptionCollection异常信息附带每个子异常的堆栈,便于并行请求失败排查。- 服务描述的
$ref属性改为与既有 schema 参数合并而非整块覆盖。 - URL 合并时复用相对 URL 的查询串对象(从而支持自定义 query aggregator)。
- 查询串解析不再把无值的空键补成悬空
=:foo&bar=baz正确解析为foo&bar=baz,而非foo=&bar=baz。 - Cookie 域名正则分隔符正确转义;加载 XML 文档时禁用网络访问。
3.8.0(2013-12-05)
- POST 文件可自定义字段名;JSON 响应解析正确遍历
additionalProperties。 BackoffPlugin自动重试 cURL 错误码 18(传输不完整);修复重试事件里把所有异常都当成CurlException访问的问题。- 修复 URL 含 fragment 时的 cURL 错误。
- 兼容不支持
CURLOPT_TIMEOUT_MS的旧版 cURL。 debug请求参数改为按"真值"判断:设 true 时输出 cURL 详细输出而非走LogPlugin。- URI 模板新增
setRegex();命令对象可返回校验错误。 - 缓存再验证(revalidation)多项修复;
AsyncPlugin与构建脚本多处清理。
四、3.7.x:请求选项体系与 Cookie/头部合规
3.7.4(2013-10-02)
- 描述参数默认值为
0时被允许(此前 0 被当作未设置)。 SchemaFormatter格式化 Unix 时间戳时返回整数。- URL 点段(dot-segment)清理更准确;最低 PHP 版本明确为5.3.3。
- 内置 cacert.pem 更新;
OauthPlugin支持把认证放入头部或查询串。
3.7.3(2013-09-08)
MultiTransferException/CommandTransferException可取出关联请求/命令的异常。additionalParameters=false在响应解析时被尊重;schema 仅在显式配置时注入响应模型。- Content-Type 不再依据请求路径猜测,只依据 EntityBody 路径猜测。
ChunkedIterator可切分\Traversable;FilterIterator改用\Iterator。- 请求序列化先访问 XML 属性再访问子节点;含引号逗号的头部正确解析;mimetype 猜测大小写不敏感。
3.7.2(2013-08-02)
- 纯 PHP 版 URI 模板展开时路径正确做 URL 编码。
- Cookie 域名严格按 RFC 6265 匹配(含 IP 地址不再匹配 Cookie,见 3.7.1)。
- OAuth 签名计算纳入 GET 参数;缓存再验证的
If-None-Match不再被双重引号包裹。 QueryString::factory()依据输入自动猜测 query aggregator;新增operation.parse_class事件用于向服务描述解析注入自定义领域对象;cURL multi 清理与优化。
3.7.1(2013-07-05)
- 客户端默认选项、HEAD 请求选项生效。
- 新增
cert、ssl_key请求选项;Host头可手工指定并与 URL 主机分离。 XmlVisitor由 SimpleXML 重写为 XMLWriter。- OAuth 参数已存在时不再重复添加;URL 无法解析时抛异常;
getContentMd5()失败返回false。 - 删除若干已废弃 API,同时修复
Collection、流工厂时序等细节。
3.7.0(2013-06-10)—— 请求选项体系成形
这一版奠定了后续使用范式,也是解读 Guzzle 3 源码的关键版本:
- 请求创建支持
$options数组:$client->get(...)系列方法尾部追加$options参数;客户端可用request.options配置为所有请求施加默认选项(默认查询串、头部、curl 选项)。 - 静态门面:
Guzzle\Http\StaticClient::mount()可把 Guzzle 挂到\Guzzle上以静态方式调用。 - 命令级
command.request_options:AbstractCommand创建的请求可注入自定义头部、查询变量、超时。 - CachePlugin 增强:可按 URI purge 全部缓存;非幂等请求自动清除匹配缓存项;利用
Vary头判定缓存命中。 Collection::setPath()支持嵌套键写入;Response实现\Serializable;execute()接受数组、单命令或Traversable。- 大量 BC 破坏(弃用/移除):
setDefaultHeaders()/getDefaultHeaders()改为读写request.options/headers配置路径;expandTemplate、getCurlMulti、setRequestFactory等从接口移除;缓存相关接口重构为CacheStorageInterface体系(cache/fetch/delete($request)、新增purge($url)与RevalidationInterface::shouldRevalidate())。
五、3.6.0 ~ 3.0.0:从组件化到重写
3.6.0(2013-05-29)
- 服务描述实现
ToArrayInterface;新增command.hidden_params黑名单,防止某些头部被当作additionalParameters。 - 可解析不完整 URL;头部混合大小写被强制为统一写法;消息内部改用
HeaderCollection实现大小写无关解析,复杂头部可通过HeaderFactory映射到专用实现(Link 头、CacheControl 头)。 - 从接口移除
setUriTemplate、setCurlMulti();RequestMediator接管receivedRequestHeader();多项$asString/$asObjects参数废弃;响应辅助函数统一返回字符串。
3.5.0(2013-05-13)
- 响应在每个 oncomplete 事件中只解析一次;一次性事件自动从
EventDispatcher移除。 MessageFormatter正确写出total_time、connect_time;克隆实体请求时同步克隆 EntityBody。- 弃用
Response::getRequest()(以浅克隆移除循环引用,利于引用计数 GC)、getPreviousResponse()(改用HistoryPlugin)。 - 新增
responseBody别名;HistoryPlugin记录"事务"(请求+响应)而非分离的对象,并支持转字符串;Response新增getEffectiveUrl()与getRedirectCount()。
3.4.x / 3.3.x
- 3.4.3:修复重定向响应重复问题;发送每个请求前重新从 phar 提取临时 cacert。
- 3.4.2:流对象支持
"a"/"a+"模式;移除与 Content-Length 冲突的Transfer-Encoding: chunked;AsyncPlugin不再强制 HEAD;日期时区在 schema formatter 中正确处理;CachePlugin支持stale-if-error;LogPlugin在 STDERR 未定义时写php://output;表单 POST 默认 utf-8;同一 key 可设置多个 POST 文件;配置加载支持远程文件。 - 3.4.1:
CurlMulti重构为"代理 + handle 池",简化实现、修复 bug 并小幅提速;并行异常正确分组;支持 PHP 5.5CurlFile(避免废弃@语法告警);OAuth 支持oauth_callback、oauth_verifier。 - 3.4.0:URL 按 RFC 3986 §5.2 解析(#289);服务描述中的绝对 URL 正确覆盖 base URL;单 PHP 数组值的查询参数解析为数组;
User-Agent规范化防重复;新增number类型;空参数从 OAuth 签名中移除;缓存再验证优先Last-Modified而非Date;默认CURLOPT_TIMEOUT提升到 150 秒以适配弱网;setBody()可自动推断 Content-Type;PSR-3LogAdapter;command.after_prepare事件;CachingEntityBody装饰器;服务描述additionalParameters定义自定义参数序列化;SSL 证书打入 phar 并按需解包。 - 3.3.1 / 3.3.0:可创建 PHP 流式响应;OAuth 多维数组签名与排序;
xmlAllowEmpty允许无 XML 参数时仍序列化 XML 体;大量性能优化;Response::json()允许标量;ErrorResponsePlugin依据服务描述errorResponses抛错;响应模型支持additionalProperties、嵌套重命名(sentAs→name);CachePlugin 支持stale-if-error与调试头。
3.2.0 ~ 3.0.x
- 3.2.0:
CurlMulti不再全局复用,改为每客户端一个以隔离实例;无路径 URL 不再默认带/;?管理权移交Guzzle\Http\Url;BadResponseException不再附带完整报文;头部逗号列表可归一为独立值;QueryString改用QueryAggregatorInterface且 URL 编码可定制;BackoffPlugin默认指数退避修复;取 Cache-Control 指令时取首个命中值。 - 3.1.2:响应解析改为 visitor 的
before()完成(如XmlVisitor在 before 中解析 XML);修复 cURL 自动解压与重定向链;CURLOPT_SSL_VERIFYHOST永不设为 1(已废弃)。 - 3.1.1 / 3.1.0:
Collection::getPath()支持通配符;ServiceBuilder 支持别名;CompositeResourceIteratorFactory;CurlException改为继承RequestException;canCache()改名canCacheRequest()/新增canCacheResponse();命令过滤从 validator 移到 location visitor。 - 3.0.7 ~ 3.0.1:phar 中 cacert 探测与自定义;
setResponseBody()接受文件名;response_body位置;无穷递归修复(缓存再验证);正文可为"0";QueryString 正确解析含等号参数;XML 属性响应支持;DefaultRequestSerializer支持数组 URI 参数;json/xml响应便捷方法;严格 CookieJar;setStream()自定义回卷行为;redirects 改由 PHP 实现而非 cURL;PECL URI 模板扩展优先;模型可用作集合对象。 - 3.0.0(2012-10-15):整体重写。服务描述格式基于 Swagger/JSON Schema,支持嵌套输入结构与响应模型、JSON/XML 输入输出、
operations替代commands;拆分为组件化顶级命名空间;移除 XML 配置与服务描述(改用数组/JSON);Cookie 归入Guzzle\Plugin\Cookie;默认携带 cURL CA 证书;仅在载荷大于 1MB 时发送Expect头;不再默认发送Accept/Accept-Encoding;引入更健壮的退避重试与缓存插件、Guzzle\Iterator组件。
六、2.x 系列要点(CHANGELOG 保留部分)
2.8.8 修复点前缀域名 Cookie 匹配与主流浏览器一致;2.8.x 引入 OAuth 双足认证、POST 字段从签名移除、json参数位置、服务描述构建/别名 JSON 加载、body_as_string规避 curl 错误 65、ReadLimitEntityBody装饰器、MockPlugin消费 mock 请求体;2.7.x 完成大量命名空间/类搬迁(Inflection、Parser),CachePlugin 默认只缓存 GET/HEAD,支持深层嵌套数组复合 URI 变量;2.6.x 引入通用 Batch 系统、AsyncPlugin、any_match约束、PostFile 类、多处 Cookie 逻辑归位与头部大小写不敏感处理;2.5.0 采用 flyweight 校验系统、移除{{ }}模板注入、回调式指数退避、微秒级 backoff、重试时回卷请求流、服务描述可禁用类型校验、ServiceDescription/ServiceBuilder可序列化。
七、源码级印证:这些修复在仓库里长什么样
CHANGELOG 条目并非空话,仓库内crmeb/vendor/guzzle/guzzle/src/Guzzle/目录(源码根目录)可逐条对照:
- HTTP 客户端骨架:Http/Client.php 定义了
REQUEST_OPTIONS = 'request.options'、CURL_OPTIONS = 'curl.options'、SSL_CERT_AUTHORITY = 'ssl.certificate_authority'、DEFAULT_SELECT_TIMEOUT = 1.0、MAX_HANDLES = 3等常量,正是 3.7.0 引入"请求选项体系"、3.9.x 围绕请求装配做边界修复的实现载体。 - 子组件齐全:目录下可见
Batch、Cache、Common、Http、Inflection、Iterator、Log、Parser、Plugin(Async/Backoff/Cache/Cookie/CurlAuth/ErrorResponse/History/Log/Md5/Mock/Oauth)、Service(Builder/Command/Description/Resource)、Stream等完整组件,印证 3.0.0 "拆分为组件化顶级命名空间" 的重构结论。 - 缓存插件生态:
Guzzle\Plugin\Cache与Guzzle\Cache同时存在,对应 CHANGELOG 3.7.0 中CacheStorageInterface接口重构与 3.9.3max-age=0TTL 修复的演进路径。 - 依赖约束:composer.lock 明确记录
guzzle/guzzle v3.9.3要求php >=5.3.3、ext-curl、symfony/event-dispatcher ~2.1,与 3.7.4 "最低 PHP 版本 5.3.3" 的记录一致。
八、它在 CRMEB 里的真实调用链:腾讯云 COS 上传
Guzzle 3 在 CRMEB 中不是孤立存在,最终服务于对象存储上传。调用链如下:
- 上传入口(配置了 COS 存储时)使用 crmeb/crmeb/services/upload/storage/Cos.php,其
initialize()读取accessKey、appid、secretKey、uploadUrl、storageName、storageRegion、cdn等配置。 app()方法实例化腾讯云 COS 客户端,将region、bucket、appid等传入Qcloud\Cos\Client。upload()通过putObject($key, $body)上传(流内容由GuzzleHttp\Psr7\Utils::streamFor()包装),并拼接cdn/uploadUrl生成最终文件 URL。- 而
Qcloud\Cos\Client内部(crmeb/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/Client.php)直接use Guzzle\Service\Description\Parameter、Guzzle\Service\Client、Guzzle\Common\Collection、Guzzle\Http\EntityBody等Guzzle 3 命名空间的类来构建请求。
因此,若你在 CRMEB 中排查 COS 上传超时、SSL 校验、Cookie/重定向等问题,阅读本文梳理的 3.9.x 与 3.8.x 修复项会非常对症;而guzzlehttp/guzzle6.5.5 面向的是另一套 PSR-7 请求场景,两者不应混用命名空间。
九、给二开者的使用与升级建议
- 不要轻易移除或升级
guzzle/guzzle:qcloud/cos-sdk-v5硬性依赖~3.7,且 composer.lock 已锁定 3.9.3;强行升级到 4/5/6(guzzlehttp/guzzle)需要同步改写 COS SDK 的类引用,超出常规二开范围。 - 区分两套命名空间:业务代码新增 HTTP 请求建议用
GuzzleHttp\Client(6.5.5);只有 COS SDK 内部才接触Guzzle\旧类,不要混用。 - 利用 CHANGELOG 定位问题:COS 上传遇到"Connection died 重连"(3.9.2)、SSL 证书(3.9.0/3.7.4/3.0.0 的 cacert 机制)、超时(3.4.0 的 150 秒默认)等,均可先在本 CHANGELOG 对应版本条目中确认行为是否符合预期。
- 版本前提:Guzzle 3 面向 PHP 5.3.3+,在 CRMEB 当前(ThinkPHP 6、较新 PHP 环境)下仍能工作,但它是官方已弃用的旧系列(composer.lock 中
suggest也提示"Guzzle 5 已迁移到新包名,Guzzle 3 已废弃"),仅作为兼容层存在,理解其能力边界即可,不必据此扩展新功能。
- 后端
- 电商
- 前端
【免费下载链接】CRMEB
🔥CRMEB开源商城免费开源多语言商城系统,Tp6框架商城,系统可商用;包含小程序商城、H5商城、公众号商城、PC商城、App,支持分销、拼团、砍价、秒杀、优惠券、积分、会员等级、小程序直播、页面DIY,前后端分离,方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程,欢迎大家提出宝贵意见和建议
相关推荐
如何捕获并美化.NET异常:Spectre.Console异常渲染实战指南
如何捕获并美化.NET异常:Spectre.Console异常渲染实战指南 Spectre.Console 是一款开源的 .NET 控制台 UI 库,它的 异常
后端电商前端CRMEB 中的 JMESPath PHP 库演进史:CHANGELOG 深度解读与源码剖析
CRMEB 中的 JMESPath PHP 库演进史:CHANGELOG 深度解读与源码剖析 导读 mtdowling/jmespath.php 是 PHP 生
后端电商前端LightTable 版本演进全解析:从 0.2.1 到 0.8.1 的 Changelog 解读与源码印证
LightTable 版本演进全解析:从 0.2.1 到 0.8.1 的 Changelog 解读与源码印证 Light Table 是一款基于 Chromiu
开发工具IDE
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考