☰
CRMEB 中的 Guzzle 3.9.3 兼容层:CHANGELOG 全量解读与 COS 上传链路源码印证
2026/10/15 18:42:51 网站建设 项目流程
  • 后端
  • 电商
  • 前端

【免费下载链接】CRMEB

🔥CRMEB开源商城免费开源多语言商城系统,Tp6框架商城,系统可商用;包含小程序商城、H5商城、公众号商城、PC商城、App,支持分销、拼团、砍价、秒杀、优惠券、积分、会员等级、小程序直播、页面DIY,前后端分离,方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程,欢迎大家提出宝贵意见和建议

项目地址:https://gitcode.com/gh_mirrors/cr/CRMEB
点击查看免费下载

本文以 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 中不是孤立存在,最终服务于对象存储上传。调用链如下:

  1. 上传入口(配置了 COS 存储时)使用 crmeb/crmeb/services/upload/storage/Cos.php,其initialize()读取accessKey、appid、secretKey、uploadUrl、storageName、storageRegion、cdn等配置。
  2. app()方法实例化腾讯云 COS 客户端,将region、bucket、appid等传入Qcloud\Cos\Client。
  3. upload()通过putObject($key, $body)上传(流内容由GuzzleHttp\Psr7\Utils::streamFor()包装),并拼接cdn/uploadUrl生成最终文件 URL。
  4. 而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,前后端分离,方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程,欢迎大家提出宝贵意见和建议

项目地址:https://gitcode.com/gh_mirrors/cr/CRMEB
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询