Răsfoiți Sursa

fix(api-test): 响应头名统一转小写,修复 staging 上 Content-Language 误报

HTTP 头名不区分大小写。staging 经 envoy 转发后头名全是小写,
用例按 'Content-Language' 取值得到 NULL,两条语言协商用例误报失败;
后端实际返回的是正确的 content-language: zh-Hans。

raw() 与 request() 返回的头名统一转小写,用例按小写取。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
visuddhinanda 5 zile în urmă
părinte
comite
8ffb9f77e1
2 a modificat fișierele cu 10 adăugiri și 6 ștergeri
  1. 2 2
      api-test/cases/06_auth.php
  2. 8 4
      api-test/src/bootstrap.php

+ 2 - 2
api-test/cases/06_auth.php

@@ -251,12 +251,12 @@ test('Accept-Language: zh-Hans → 中文错误文案 + Content-Language', funct
     $res = auth_wrong_code_in('zh-Hans');
     $res = auth_wrong_code_in('zh-Hans');
     assert_field_error('code', $res, 'invites 错验证码(zh-Hans)');
     assert_field_error('code', $res, 'invites 错验证码(zh-Hans)');
     assert_eq('验证码不正确或已过期。', $res['body']['errors']['code'][0] ?? null, 'errors.code');
     assert_eq('验证码不正确或已过期。', $res['body']['errors']['code'][0] ?? null, 'errors.code');
-    assert_eq('zh-Hans', $res['headers']['Content-Language'][0] ?? null, 'Content-Language');
+    assert_eq('zh-Hans', $res['headers']['content-language'][0] ?? null, 'Content-Language');
 });
 });
 
 
 test('Accept-Language: zh-TW → 繁体;不支持的语言 → en', function () {
 test('Accept-Language: zh-TW → 繁体;不支持的语言 → en', function () {
     $hant = auth_wrong_code_in('zh-TW');
     $hant = auth_wrong_code_in('zh-TW');
     assert_eq('驗證碼不正確或已過期。', $hant['body']['errors']['code'][0] ?? null, 'zh-TW 的 errors.code');
     assert_eq('驗證碼不正確或已過期。', $hant['body']['errors']['code'][0] ?? null, 'zh-TW 的 errors.code');
     $fr = auth_wrong_code_in('fr-FR');
     $fr = auth_wrong_code_in('fr-FR');
-    assert_eq('en', $fr['headers']['Content-Language'][0] ?? null, 'fr-FR 的 Content-Language');
+    assert_eq('en', $fr['headers']['content-language'][0] ?? null, 'fr-FR 的 Content-Language');
 });
 });

+ 8 - 4
api-test/src/bootstrap.php

@@ -70,7 +70,7 @@ function api(string $class, ?string $token = null): object
 }
 }
 
 
 /**
 /**
- * 统一执行一次请求,返回 ['status'=>int, 'body'=>?array, 'headers'=>array]。
+ * 统一执行一次请求,返回 ['status'=>int, 'body'=>?array, 'headers'=>array](头名已转小写)。
  * $fn 必须返回 WithHttpInfo 的三元组 [$content, $status, $headers]。
  * $fn 必须返回 WithHttpInfo 的三元组 [$content, $status, $headers]。
  * 非 2xx 时生成的客户端抛 ApiException,这里捕获并解出状态码与 body。
  * 非 2xx 时生成的客户端抛 ApiException,这里捕获并解出状态码与 body。
  */
  */
@@ -79,7 +79,7 @@ function request(callable $fn): array
     try {
     try {
         [$content, $status, $headers] = $fn();
         [$content, $status, $headers] = $fn();
 
 
-        return ['status' => $status, 'body' => normalize($content), 'headers' => $headers];
+        return ['status' => $status, 'body' => normalize($content), 'headers' => array_change_key_case($headers, CASE_LOWER)];
     } catch (ApiException $e) {
     } catch (ApiException $e) {
         $status = $e->getCode();
         $status = $e->getCode();
         // 网络层错误(DNS/连接/超时)时,生成客户端把异常包成 ApiException 但 code 不是
         // 网络层错误(DNS/连接/超时)时,生成客户端把异常包成 ApiException 但 code 不是
@@ -89,7 +89,7 @@ function request(callable $fn): array
         }
         }
         $body = json_decode((string) $e->getResponseBody(), true);
         $body = json_decode((string) $e->getResponseBody(), true);
 
 
-        return ['status' => $status, 'body' => is_array($body) ? $body : null, 'headers' => $e->getResponseHeaders()];
+        return ['status' => $status, 'body' => is_array($body) ? $body : null, 'headers' => array_change_key_case($e->getResponseHeaders() ?? [], CASE_LOWER)];
     }
     }
 }
 }
 
 
@@ -119,7 +119,11 @@ function raw(string $method, string $path, ?array $query = null, ?array $json =
     }
     }
     $body = json_decode((string) $resp->getBody(), true);
     $body = json_decode((string) $resp->getBody(), true);
 
 
-    return ['status' => $resp->getStatusCode(), 'body' => is_array($body) ? $body : null, 'headers' => $resp->getHeaders()];
+    // 头名一律转小写:HTTP 头名不区分大小写,staging 经 envoy 转发后全是小写,
+    // 本地 artisan serve 则是 Content-Language 这种写法,按原样取会两边不一致。
+    $headers = array_change_key_case($resp->getHeaders(), CASE_LOWER);
+
+    return ['status' => $resp->getStatusCode(), 'body' => is_array($body) ? $body : null, 'headers' => $headers];
 }
 }
 
 
 function normalize(mixed $content): mixed
 function normalize(mixed $content): mixed