不能直接用thinkphp的http::post()硬发,因azure语言服务已统一为/language/:analyze-text终结点,强制要求正确api-version、authorization/ocp-apim-subscription-key认证头、严格json结构(含kind/parameters/analysisinput三层嵌套)及iso 639-1语言码,否则返回401或400。

ThinkPHP 项目直接调用 Azure 认知服务(文本翻译、情感分析)不依赖扩展或 SDK,核心是构造合规的 HTTP 请求 —— 但必须注意 api-version、Content-Type、认证头格式和请求体结构,稍有偏差就会返回 401 Unauthorized 或 400 Bad Request。
为什么不能直接用 ThinkPHP 的 Http::post() 硬发?
Azure 语言服务(包括情感分析、实体识别等)已统一为 /language/:analyze-text 终结点,且强制要求 JSON 请求体含 kind 字段;而旧版 /text/analytics/v3.1/ 路径已弃用。直接套用老教程的 URL 和 body 格式会失败。
- 新版终结点必须是形如
https://<your-resource-name>.cognitiveservices.azure.com/language/:analyze-text?api-version=2022-05-01</your-resource-name>,其中api-version不能省略或写错 - 请求头必须包含
Authorization: Bearer <token></token>(使用 AAD token)或Ocp-Apim-Subscription-Key: <key></key>(更常用),二者不可混用 - 请求体必须是严格 JSON,且顶层字段为
kind(如"sentiment")、parameters、analysisInput,不能少一层或多一层
如何用 Guzzle 发起符合 Azure 要求的情感分析请求?
推荐使用 Guzzle(ThinkPHP 8+ 默认支持),避免手写 cURL 容易遗漏 header 或编码问题。关键不是“能不能发”,而是字段名、嵌套层级、语言代码是否匹配 Azure 当前 API 规范。
- 安装 Guzzle:
composer require guzzlehttp/guzzle - 情感分析请求示例(单文档):
$client = new \GuzzleHttp\Client();
$response = $client->post('https://<your-endpoint>.cognitiveservices.azure.com/language/:analyze-text?api-version=2022-05-01', [
'headers' => [
'Ocp-Apim-Subscription-Key' => '<your-key>',
'Content-Type' => 'application/json'
],
'json' => [
'kind' => 'sentiment',
'parameters' => ['modelVersion' => 'latest'],
'analysisInput' => [
'documents' => [
['id' => '1', 'language' => 'zh', 'text' => '这个产品太棒了!']
]
]
]
]);
$data = json_decode($response->getBody(), true);
// 情感结果在 $data['results']['documents'][0]['sentiment'],置信度在 $data['results']['documents'][0]['confidenceScores']</your-key></your-endpoint>
- 注意:
language必须是 ISO 639-1 代码(如zh、en),不能写zh-CN,否则返回InvalidLanguageCode - 返回结果中
sentiment值为positive/negative/neutral,不是数字分值
文本翻译为何要用独立终结点,且必须带 region?
Azure 文本翻译(Translator)和语言服务(Language)是两个不同资源、不同终结点、不同认证方式的服务。翻译服务不走 /language/,必须用 https://api.translator.azure.cn/translate?api-version=3.0,且若使用资源密钥认证,需额外传 Ocp-Apim-Subscription-Region 头 —— 这个值是你创建 Translator 资源时选的区域(如 eastasia),不是语言服务的 region。
- 常见错误:把语言服务的
region设置(仅用于 translate 函数的数据库扩展)误当成翻译 API 的Ocp-Apim-Subscription-Region头 - 翻译请求体是数组而非单文档对象,且必须指定
to目标语言(如["ja"]) - 示例片段:
$response = $client->post('https://api.translator.azure.cn/translate?api-version=3.0&to=ja', [
'headers' => [
'Ocp-Apim-Subscription-Key' => '<your-translator-key>',
'Ocp-Apim-Subscription-Region' => 'eastasia', // 必填,与资源所在区域一致
'Content-Type' => 'application/json'
],
'json' => [['text' => '今天天气很好']]
]);</your-translator-key>
ThinkPHP 中怎么安全存取密钥和终结点?
绝对不要把 subscription-key 或终结点硬编码在控制器里。ThinkPHP 的 .env 是唯一合理位置,但要注意变量名别和框架内置变量冲突(如避免用 AZURE_KEY,改用 AZURE_LANGUAGE_KEY)。
- 在
.env中写:
AZURE_LANGUAGE_ENDPOINT=https://your-resource.cognitiveservices.azure.com AZURE_LANGUAGE_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx AZURE_TRANSLATOR_KEY=yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy AZURE_TRANSLATOR_REGION=eastasia
- 控制器中读取:
Env::get('AZURE_LANGUAGE_KEY'),再传给 Guzzle 配置 - 切记:.env 文件不能被 Web 直接访问,检查
public/.htaccess或 Nginx 配置是否屏蔽了它
真正容易被忽略的是:Azure 语言服务对中文文本的情绪判断默认较保守,短句(如“不错”“还行”)常判为 neutral 而非 positive;若业务强依赖细粒度情绪,得结合上下文批量分析或启用 opinionMining 模式(需修改 kind 为 sentiment_opinion_mining 并调整 response 解析逻辑)。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











