Laravel如何让控制器表单提交后实例化的对象在所有方法可用
问题核心原因
HTTP 协议为无状态协议,Laravel 处理每个独立请求时都会重新实例化对应的控制器类。你在getAuthUrl请求中给$this->console属性赋值的操作仅在当前请求生命周期内有效,跳转至 callback 路由后触发的是全新请求,控制器实例重新初始化,$console属性未被赋值,自然返回 null。
由于 Console 对象包含闭包无法序列化存入 Session,我们可以将实例化 Console 所需的可序列化参数(client_id、client_secret)存入 Session 跨请求传递,需要用到实例时再动态构造即可,无需存储完整对象。
调整后代码示例
控制器直接实现版本
class SearchConsoleController extends Controller { private $callback; protected function __construct() { $this->callback = route('searchconsole.callback'); } private function setConsole($clientId, $clientSecret){ return new Console(new Google_Client(), $clientId, $clientSecret, $this->callback); } public function index(Request $request) { return view('searchconsole.index'); } public function getAuthUrl(Request $request) { $clientId = $request->get('google-client-id'); $clientSecret = $request->get('google-client-secret'); // 将参数存入Session实现跨请求传递 session([ 'google_client_id' => $clientId, 'google_client_secret' => $clientSecret ]); $console = $this->setConsole($clientId, $clientSecret); return $console->getAuthUrl(); } public function callback(Request $request){ if ($request->has('code')) { // 从Session读取参数重新实例化Console $clientId = session('google_client_id'); $clientSecret = session('google_client_secret'); if (empty($clientId) || empty($clientSecret)) { die('缺少授权必要参数,请重新提交表单'); } $console = $this->setConsole($clientId, $clientSecret); $console->acceptCode($request->get('code')); return redirect()->action('SearchConsoleController@listSites', [$request]); } else{ die('error'); } } }
ServiceProvider 实现版本
首先修正你之前 ServiceProvider 中回调地址获取的错误,调整绑定逻辑:
namespace App\Providers; use Illuminate\Support\ServiceProvider; use App\Helpers\Console; use Google_Client; class AppServiceProvider extends ServiceProvider { public function register() { $this->app->bind(Console::class, function() { $request = request(); // 优先从Session取参数适配callback请求,其次取当前请求参数 $clientId = session('google_client_id', $request->get('google-client-id')); $clientSecret = session('google_client_secret', $request->get('google-client-secret')); $callback = route('searchconsole.callback'); return new Console(new Google_Client(), $clientId, $clientSecret, $callback); }); } public function boot(){} }
绑定完成后可直接在控制器方法中通过依赖注入获取 Console 实例,无需手动构造:
public function getAuthUrl(Request $request, Console $console) { session([ 'google_client_id' => $request->get('google-client-id'), 'google_client_secret' => $request->get('google-client-secret') ]); return $console->getAuthUrl(); } public function callback(Request $request, Console $console){ if ($request->has('code')) { $console->acceptCode($request->get('code')); return redirect()->action('SearchConsoleController@listSites', [$request]); } die('error'); }
额外说明
你提到最终解决方案可正常运行,只是误启动了错误应用,这类问题可以优先排查运行环境、项目入口是否匹配,减少不必要的代码调整成本。
内容的提问来源于stack exchange,提问作者skytorner
相关产品推荐
相关产品推荐

