PAYATHON 2026

Laravel 5.3 API route 无法访问且方法未执行

支付阿杰

结论

如果路由定义在 Laravel 5.3 的 routes/api.php 中,Laravel 默认会为它添加 /api 前缀。因此,实际访问地址应为:

http://anaketesting.tk/api/product-service/payment-notification

原地址少了 /api:

http://anaketesting.tk/product-service/payment-notification

这个请求通常匹配不到对应的 API 路由,所以控制器的 notification() 方法不会执行,方法中的日志和文件写入也不会发生。

正确的路由定义

在 routes/api.php 中定义路由:

<?php

Route::get('product-service/payment-notification', [
    'as'   => 'productService.notification',
    'uses' => 'ProductServiceController@notification',
]);

访问地址为:

GET /api/product-service/payment-notification

如果不想让 URL 包含 /api,可以把路由放到 routes/web.php,也可以修改 app/Providers/RouteServiceProvider.php 中 API 路由组的前缀。不过,修改全局前缀会影响其他接口,通常不建议为了一个接口这样处理。

先确认 Laravel 实际注册了什么路由

在项目目录运行:

php artisan route:list

查看输出中的 URI、请求方法和控制器,例如:

GET|HEAD  api/product-service/payment-notification

如果列表中没有对应记录,先清除路由缓存,再重新检查:

php artisan route:clear
php artisan cache:clear
php artisan route:list

生产环境如果需要缓存路由,可以在确认配置无误后运行:

php artisan route:cache

通过 route:list 可以直接判断问题出在路由注册阶段,还是控制器执行阶段。

改正控制器中的请求记录方式

下面这段代码还有一个问题:

file_put_contents(
    storage_path().'/notification_'.$date.'.json',
    \Response::json($request)
);

\Response::json() 返回的是 HTTP 响应对象,不适合直接作为 JSON 字符串写入文件。记录请求内容时,应先读取请求数据,再进行编码:

<?php

use Carbon\Carbon;
use Illuminate\Http\Request;

public function notification(Request $request)
{
    $date = Carbon::now()->format('YmdHis');

    file_put_contents(
        storage_path('notification_'.$date.'.json'),
        json_encode(
            $request->all(),
            JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT
        )
    );

    return response()->json([
        'CREATED' => true,
    ], 201);
}

如果需要保存未经解析的原始请求体,可以使用:

file_put_contents(
    storage_path('notification_'.$date.'.json'),
    $request->getContent()
);

调试时,可以先把请求写入 Laravel 日志:

\Log::info('Payment notification received', [
    'method'  => $request->method(),
    'headers' => $request->headers->all(),
    'payload' => $request->all(),
    'raw'     => $request->getContent(),
]);

日志通常位于:

storage/logs/laravel.log

确认回调使用的 HTTP 方法

当前路由只接受 GET 请求:

Route::get(...)

支付通知、Webhook 和服务器回调通常使用 POST。如果对方发送的是 POST 请求,这条 GET 路由就不会执行,需要改成:

Route::post('product-service/payment-notification', [
    'as'   => 'productService.notification',
    'uses' => 'ProductServiceController@notification',
]);

排查时也可以临时允许多种请求方法:

Route::match(
    ['get', 'post'],
    'product-service/payment-notification',
    'ProductServiceController@notification'
);

确认第三方平台使用的请求方法后,最好再将路由限制为对应的方法。

仍然无法访问时的检查顺序

  1. 运行 php artisan route:list,确认完整 URI 和请求方法。
  2. 如果路由位于 routes/api.php,使用带 /api 前缀的地址。
  3. 确认客户端发送的是 GET 还是 POST。
  4. 清除可能已经过期的路由缓存。
  5. 检查站点根目录是否指向 Laravel 项目的 public 目录。
  6. 检查 Apache 或 Nginx 是否将请求正确转发到 public/index.php。
  7. 确认 Web 服务进程对 storage 和 bootstrap/cache 目录有写入权限。
  8. 查看 Web 服务器的访问日志和错误日志。如果请求没有进入 Laravel,storage/logs/laravel.log 通常不会留下记录。

浏览器地址栏发出的通常是 GET 请求。因此,通过浏览器访问只能验证 GET 路由是否可达,不能证明第三方发送的 POST 回调能够正常处理。

最可能的直接原因是 routes/api.php 自动添加了 /api 前缀。之后还需要确认支付通知实际使用的 HTTP 方法。先运行 php artisan route:list 查看最终注册的路由,通常就能定位问题。

备注:内容仅供参考。