Codeigniter 4 REST API客户端请求出现301永久重定向错误求助
问题:Codeigniter 4 REST API 客户端请求返回301 Moved Permanently,Postman可正常访问
环境:Laragon 5.0.0210523(Apache-2.4.47、PHP-8.1.7、MongoDB-4.0.28),搭建了集成firebase/php-jwt的Codeigniter 4 REST API应用。此前服务端与客户端均运行正常,停止Laragon服务次日重启后,客户端请求返回301错误,但Postman可正常访问API。已尝试重启Apache、MongoDB服务及Windows系统,排查URL错误无效,需解决方案。
REST API服务端配置
composer.json
*** "require": { "php": "^7.4 || ^8.0", "codeigniter4/framework": "^4.0", "mongodb/mongodb": "^1.12", "firebase/php-jwt": "^6.3" }, ***
.env文件
*** JWT_SECRET_KEY = SomeThing$089 JWT_TIME_TO_LIVE = 3600 app.baseURL = 'http://ci4-api.localhost' ***
Route.php
*** $routes->get('/', 'Home::index'); $routes->resource('api/users'); $routes->post('api/auth', [\App\Controllers\Api\Auth::class, 'index']); ***
JWT_Helper.php
use App\Models\ModelUsers; use Firebase\JWT\JWT; use Firebase\JWT\Key; /** * @throws Exception */ function getJWT($authHeader) { if (is_null($authHeader)){ throw new Exception("Authentication JWT failed"); } return explode(" ", $authHeader)[1]; } function validateJWT($encodedToken) { $key = getenv('JWT_SECRET_KEY'); $decodedToken = JWT::decode($encodedToken, new Key($key, 'HS256')); $modelUsers = new ModelUsers(); $modelUsers->get_email($decodedToken->email); } function createJWT($email): string { $timeRequest = time(); $timeToken = getenv('JWT_TIME_TO_LIVE'); $timeExpired = $timeRequest + $timeToken; $payload = [ 'email' => $email, 'iat' => $timeRequest, 'exp' => $timeExpired, ]; return JWT::encode($payload, getenv('JWT_SECRET_KEY'), 'HS256'); }
FilterJWT.php
namespace App\Filters; use CodeIgniter\API\ResponseTrait; use CodeIgniter\Filters\FilterInterface; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; use Config\Services; use Exception; class FilterJWT implements FilterInterface { use ResponseTrait; public function before(RequestInterface $request, $arguments = null) { $header = $request->getServer('HTTP_AUTHORIZATION'); try { helper('jwt'); $encodedToken = getJWT($header); validateJWT($encodedToken); return $request; } catch (Exception $ex) { return Services::response()->setJSON( [ 'error' => $ex->getMessage(), ] )->setStatusCode(ResponseInterface::HTTP_UNAUTHORIZED); } } public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) { // TODO: Implement after() method. } }
Filters.php
*** public $aliases = [ 'csrf' => CSRF::class, 'toolbar' => DebugToolbar::class, 'honeypot' => Honeypot::class, 'invalidchars' => InvalidChars::class, 'secureheaders' => SecureHeaders::class, 'auth' => FilterJWT::class, ]; public $filters = [ 'auth' => [ 'before' => [ 'api/users/*', 'api/users' ] ] ]; ***
ModelUsers.php
namespace App\Models; use App\Libraries\MongoDb; class ModelUsers { private $database = 'ci4_api'; private $collection = 'user'; private $conn; function __construct() { $mongodb = new MongoDb(); $this->conn = $mongodb->getConn(); } function get_user_list() { try { $filter = []; $query = new \MongoDB\Driver\Query($filter); $result = $this->conn->executeQuery($this->database. '.' . $this->collection, $query); return $result->toArray(); } catch (\MongoDB\Driver\Exception\RuntimeException $ex) { show_error('Error while fetching users: ' . $ex->getMessage(), 500); } } ***
Auth.php
namespace App\Controllers\Api; use App\Controllers\BaseController; use App\Models\ModelUsers; use CodeIgniter\API\ResponseTrait; use CodeIgniter\Validation\Validation; use Config\Services; class Auth extends BaseController { use ResponseTrait; private ModelUsers $model; private Validation $validation; function __construct() { $this->model = new ModelUsers(); $this->validation = Services::validation(); } public function index() { $email = $this->request->getVar('email'); $password = $this->request->getVar('password'); $password_hash = password_hash($password, PASSWORD_DEFAULT); $data1 = [ 'email' => $email, 'password' => $password ]; if (!$this->validation->run($data1, 'login')) { $errors = $this->validation->getErrors(); $response = [ 'status' => 201, 'error' => null, 'messages' => [ 'errors' => [ $errors ] ], ]; return $this->respond($response); } $data1 = $this->model->get_email($email); //return $this->respond($data1, 200); if (!$data1) { $response = [ 'status' => 201, 'error' => null, 'messages' => [ 'error' => 'Data user atau password tidak ada1' ], ]; return $this->respond($response, 200); } $password_user = $data1->password; if (password_verify($password_hash, $password_user) != 0){ $response = [ 'status' => 201, 'error' => null, 'messages' => [ 'error' => 'Data user atau password tidak ada2' ], ]; return $this->respond($response, 200); } helper('jwt'); $response = [ 'message' => 'Auth berhasil dilakukan', 'data' => $data1, 'access_token' => createJWT($email) ]; return $this->respond($response, 200); } ***
Users.php
namespace App\Controllers\Api; use App\Controllers\BaseController; use App\Models\ModelUsers; use CodeIgniter\API\ResponseTrait; use CodeIgniter\HTTP\Response; use CodeIgniter\Validation\Validation; use Config\Services; class Users extends BaseController { use ResponseTrait; private ModelUsers $model; private Validation $validation; function __construct() { $this->model = new ModelUsers(); $this->validation = Services::validation(); } public function index(): Response { $data = $this->model->get_user_list(); $count = count($data); if ($count <= 0) { $data = [ 'status' => 201, 'error' => null, 'message' => [ 'success' => 'Tidak ada data daftar pegawai' ], ]; } return $this->respond($data, 200); } ***
REST客户端配置
.env文件
*** app.baseURL = 'http://ci4-test.localhost' ***
Routes.php
*** $routes->get('/rest', [\App\Controllers\Rest\RestClient::class, 'index']); ***
RestClient.php
namespace App\Controllers\Rest; use App\Controllers\BaseController; use Config\Services; class RestClient extends BaseController { public function index() { $client = Services::curlrequest(); $token = "someToken"; $url = "http://ci4-api.localhost/api/users/"; $headers = [ 'Authorization' => 'Bearer ' . $token, ]; $response = $client->request('GET', $url, ['headers' => $headers, 'http_errors' => false]); return $response->getBody(); } }
Postman测试情况
- API认证请求正常
- 获取用户列表请求正常
解决方案
1. 修正客户端请求URL的末尾斜杠
Codeigniter 4路由默认会对带末尾斜杠的URL返回301重定向(如/api/users/ → /api/users),Postman会自动跟随重定向,但CURL请求默认不处理。
修改客户端RestClient.php中的URL为:
$url = "http://ci4-api.localhost/api/users"; // 去掉末尾斜杠
2. 开启CURL跟随重定向
如果需要保留斜杠,可在CURL请求中添加重定向配置:
$response = $client->request('GET', $url, [ 'headers' => $headers, 'http_errors' => false, 'allow_redirects' => [ 'max' => 5, // 最大重定向次数 'strict' => true, 'referer' => true ] ]);
3. 检查服务端.htaccess配置
确认服务端项目根目录的.htaccess文件存在且配置正确,避免Apache重写规则异常:
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php/$1 [L]
4. 清除Codeigniter缓存
重启Laragon后可能存在缓存问题,删除服务端项目writable/cache目录下的所有文件,强制刷新路由配置。
5. 验证Apache虚拟主机配置
确认Laragon的虚拟主机配置中,ci4-api.localhost的根目录正确指向API项目,避免请求被路由到错误位置。
内容的提问来源于stack exchange,提问作者santo
相关产品推荐
相关产品推荐

