为啥 GuzzleHttp 客户端在 Laravel/Lumen 上使用它发出网络请求时会抛出 ClientException?

Posted

技术标签:

【中文标题】为啥 GuzzleHttp 客户端在 Laravel/Lumen 上使用它发出网络请求时会抛出 ClientException?【英文标题】:Why GuzzleHttp client throws ClientException when using it to make network request on Laravel/Lumen?为什么 GuzzleHttp 客户端在 Laravel/Lumen 上使用它发出网络请求时会抛出 ClientException? 【发布时间】:2019-10-15 15:39:54 【问题描述】:

我目前正在使用 Laravel/Lumen 微框架构建一个金融微服务应用程序。一切都按预期完美运行。我现在的问题是我正在尝试使用GuzzleHttp 客户端通过来自ApiGateway 的Api 调用向我的内部服务发出网络请求。问题是当我向内部服务发出请求时,它总是抛出 ClientException 异常。

客户端异常

客户端错误:GET http://127.0.0.1:8081/v1/admin 导致 401 Unauthorized 响应:"error":"Unauthorized.","code":401

我尝试使用 postman 向相同的内部服务发出网络请求;它工作正常。但是,由于某种原因仍然无法使用GuzzleHttp。我不知道我做错了什么。我们将不胜感激。

这里是 ApiGateway 中的 httpClient.php。

//Constructor method
public function __construct() 
    $this->baseUri = config('services.auth_admin.base_uri');


public function httpRequest($method, $requestUrl, $formParams = [], $headers = []) 
    //Instantiate the GazzleHttp Client
    $client = new Client([
        'base_uri' => $this->baseUri,
    ]);
    //Send the request
    $response = $client->request($method, $requestUrl, ['form_params' => $formParams, 'headers' => $headers]);
    //Return a response
    return $response->getBody();


//Internal Service Communication in ApiGateway** 
public function getAdmin($header) 
    return $this->httpRequest('GET', 'admin', $header);

InternalServiceController.php

   public function getAdmin(Request $request) 
        return $this->successResponse($this->authAdminService->getAdmin($request->header()));
    

我正在使用 Lumen 版本:5.8 和 GuzzleHttp 版本:6.3

【问题讨论】:

401 错误表示您未通过身份验证,听起来您需要将 API 令牌与请求一起发送。 这就是我困惑的原因;当我 dd($request->header()) 并且内部客户端期望令牌位于请求标头上时,请求标头包含有效令牌。 你能把传递给方法的 headers 数组包含进去吗? 你能把 $client->request($method, $requestUrl, ['form_params' => $formParams, 'headers' => $headers]) 改成 $client->request($method , $requestUrl, ['query' => $formParams, 'headers' => $headers]) 当你使用 GET 方法时? API是否需要json格式的数据?如果是,您是否将 application/json 作为内容类型传递?如果仍然是,那么使用 form_params 将无济于事。您应该改用json。除此之外,身份验证是基本的吗?如果是,那么您的标题应该是这种格式,$header['Authorization'] = "Basic ".base64_encode('your_api_key:your_api_secret_here'); 【参考方案1】:

我在这里做了一些假设,希望对你有所帮助。

php 不支持跳过可选参数,因此您应该在调用httpRequest() 时传递一个空数组[]。

public function httpRequest($method, $requestUrl, $formParams = [], $headers = [], $type='json', $verify = false) 
    //Instantiate the GazzleHttp Client
    $client = new Client([
        'base_uri' => $this->baseUri,
    ]);

    //the request payload to be sent
    $payload = [];

    if (!$verify) 
       $payload['verify'] = $verify; //basically for SSL and TLS
    

    //add the body to the specified payload type
    $payload[$type] = $formParams;

    //check if any headers have been passed and add it as well
    if(count($headers) > 0) 
        $payload['headers'] = $headers;
    

    //Send the request
    $response = $client->request($method, $requestUrl, $payload);
    //Return a response
    return $response->getBody();

现在你需要在不传入任何form_params或body的时候以这种方式调用它

//Internal Service Communication in ApiGateway** 
 public function getAdmin($header) 
     return $this->httpRequest('GET', 'admin', [], $header);
 

【讨论】:

【参考方案2】:

您将标题作为 formParams 传递(第三个索引而不是第四个)。

试试下面:

return $this->httpRequest('GET', 'admin', [], $header);

【讨论】:

是的,我完全理解;我试过了,还是不行。 您能否更新您的示例,以便我们看到您理解? - 很难根据有错误的示例代码提供帮助 感谢您的回答;当时非常有帮助;我刚回来接受你的回答。

以上是关于为啥 GuzzleHttp 客户端在 Laravel/Lumen 上使用它发出网络请求时会抛出 ClientException?的主要内容,如果未能解决你的问题,请参考以下文章

CodeIgniter GuzzleHttp 403 禁止

GuzzleHTTP在现有页面上返回404

guzzlehttp/guzzle

GuzzleHttp Laravel - 无法解析主机:myapplication.dev

Tp6使用GuzzleHttp访问http

Tp6使用GuzzleHttp访问http