Laravel 如何携带 order id 重定向到另一个 Controller?
结论
redirect() 会让浏览器发起新的 GET 请求,不会向目标路由发送 POST。由于当前路由使用了 Route::post(),无法匹配这个 GET 请求,因此会抛出 MethodNotAllowedHttpException。
如果 /pay/{orderId} 用来展示或进入支付页面,建议改用 GET 路由,并让路由参数 {orderId} 与 Controller 方法中的 $orderId 保持一致。
推荐写法:使用 GET 路由
OrderController
if (request('payment_method') === 'online') {
return redirect()->route('payments.pay', [
'orderId' => $order->id,
]);
}
web.php
较新的 Laravel 项目可以使用 Controller 类数组语法:
use App\Http\Controllers\PublicSslCommerzPaymentController;
Route::get('/pay/{orderId}', [PublicSslCommerzPaymentController::class, 'index'])
->name('payments.pay');
旧版 Laravel 也可以继续使用字符串语法:
Route::get('/pay/{orderId}', 'PublicSslCommerzPaymentController@index')
->name('payments.pay');
PublicSslCommerzPaymentController
use Illuminate\Http\Request;
class PublicSslCommerzPaymentController extends Controller
{
public function index(Request $request, $orderId)
{
// $orderId 就是 URL 中的订单 ID
$order = Order::findOrFail($orderId);
// 继续处理支付逻辑
}
}
路由参数是 {orderId},Controller 中也建议写成 $orderId。虽然某些情况下 Laravel 会按位置注入参数,但使用相同的名称更清楚,也能减少后续维护时的歧义。
使用路由模型绑定
如果项目使用 Order 作为订单模型,可以让 Laravel 根据 ID 自动查询订单:
use App\Models\Order;
use App\Http\Controllers\PublicSslCommerzPaymentController;
Route::get('/pay/{order}', [PublicSslCommerzPaymentController::class, 'index'])
->name('payments.pay');
重定向时直接传入订单模型:
return redirect()->route('payments.pay', [
'order' => $order,
]);
Controller 直接接收 Order:
public function index(Order $order)
{
// $order 已经是查询到的订单模型
}
找不到对应订单时,Laravel 会返回 404。
如果目标路由必须使用 POST
HTTP 重定向不能把普通的 GET 跳转变成 POST 请求。如果支付接口必须接收 POST,应通过表单提交,而不是调用 redirect():
<form method="POST" action="{{ route('payments.pay', ['orderId' => $order->id]) }}">
@csrf
<button type="submit">前往支付</button>
</form>
路由仍然使用 POST:
Route::post('/pay/{orderId}', [PublicSslCommerzPaymentController::class, 'index'])
->name('payments.pay');
Controller:
public function index(Request $request, $orderId)
{
$order = Order::findOrFail($orderId);
// 处理 POST 请求
}
如果业务要求在创建订单后立即自动提交到支付路由,可以返回一个带有隐藏字段并自动提交的页面:
<form id="payment-form"
method="POST"
action="{{ route('payments.pay', ['orderId' => $order->id]) }}">
@csrf
</form>
<script>
document.getElementById('payment-form').submit();
</script>
更常见的处理方式是:通过 POST 创建订单,创建成功后重定向到 GET 支付页面,再由支付页面提交后续操作。
注意事项
不要在 Laravel Controller 中手动调用:
session_start();
Laravel 已通过中间件管理 Session。如果需要保存或读取订单 ID,应使用 Laravel 提供的 Session API:
session(['order_id' => $order->id]);
$orderId = session('order_id');
本例已经通过路由参数传递订单 ID,通常不必再写入 Session。
订单 ID 出现在 URL 中,并不代表当前用户有权操作该订单。查询订单时还要验证订单归属和支付状态,例如:
$order = Order::where('id', $orderId)
->where('user_id', auth()->id())
->firstOrFail();
用于展示支付页面时使用 GET 路由。必须执行 POST 操作时,则通过表单提交,不能依靠 redirect() 发送 POST。
备注:内容仅供参考。
