You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Laravel Passport密码授权及Guzzle时服务器卡顿问题排查

问题根源:请求阻塞(不是Guzzle或Passport的锅)

你遇到的卡顿问题,本质上是请求死锁导致的,和Guzzle、Passport本身没有直接关系。

原因很简单:当你在Laravel的login方法里用Guzzle发起请求到http://localhost:8000/oauth/token时,如果你用的是Laravel内置的开发服务器(php artisan serve),它是单线程/单进程的——当前请求还在处理中,新的Guzzle请求会被服务器挂起,等着当前进程释放资源,而当前进程又在等着Guzzle的请求返回,形成了互相等待的死锁,所以会一直卡顿。

而Postman是外部独立请求,和当前处理login方法的进程无关,服务器可以正常处理,所以没有问题。

解决方案:避免内部HTTP调用,直接用Passport的底层逻辑

既然是同一个应用,完全没必要通过Guzzle发起HTTP请求来获取令牌,直接调用Passport的内部逻辑就能生成令牌,既高效又不会有阻塞问题。

这里提供两种可行的方案:

方案1:直接为验证通过的用户生成令牌

如果你的场景是用户登录后获取令牌,可以先验证用户凭证,再直接创建令牌:

use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;

public function login(Request $request)
{
    // 验证用户名和密码是否正确
    if (!Auth::attempt($request->only('username', 'password'))) {
        return response()->json(['error' => '用户名或密码错误'], 401);
    }

    $user = Auth::user();
    // 创建密码授权类型的访问令牌
    $tokenResult = $user->createToken('Mobile App Access Token');
    $token = $tokenResult->accessToken;

    // 返回令牌信息
    return response()->json([
        'access_token' => $token,
        'token_type' => 'Bearer',
        'expires_at' => Carbon::parse(
            $tokenResult->token->expires_at
        )->toDateTimeString()
    ]);
}

方案2:内部转发请求到Passport的令牌接口

如果你想严格遵循OAuth2的密码授权流程(比如要复用Passport的参数验证、令牌过期逻辑),可以内部转发请求到/oauth/token,而不是用Guzzle发起外部请求:

use Laravel\Passport\Client;
use Illuminate\Http\Request as LaravelRequest;
use League\OAuth2\Server\Exception\OAuthServerException;

public function login(Request $request)
{
    // 获取密码授权类型的客户端(你之前配置的password client)
    $passwordClient = Client::where('password_client', true)->first();

    if (!$passwordClient) {
        return response()->json(['error' => '未找到密码授权客户端'], 500);
    }

    try {
        // 构建令牌请求所需的参数
        $request->merge([
            'grant_type' => 'password',
            'client_id' => $passwordClient->id,
            'client_secret' => $passwordClient->secret,
            'scope' => '*',
        ]);

        // 内部创建POST请求到/oauth/token
        $proxyRequest = LaravelRequest::create(
            '/oauth/token',
            'POST',
            $request->all()
        );

        // 让应用处理这个内部请求,返回令牌响应
        $response = app()->handle($proxyRequest);

        return json_decode($response->getContent(), true);
    } catch (OAuthServerException $e) {
        return response()->json(['error' => $e->getMessage()], $e->getHttpStatusCode());
    }
}
额外提示:生产环境注意事项

如果你的生产环境用的是多进程服务器(比如Nginx+PHP-FPM),理论上不会出现单进程阻塞的问题,但依然不推荐用Guzzle调用自己的API——内部调用逻辑的性能要比HTTP请求高得多,还能避免网络层面的潜在问题。

内容的提问来源于stack exchange,提问作者Bruno Gutierrez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:19:39