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

本地前后端对接异常:LiveServer+XAMPP接口请求返回空内容

前后端对接异常排查求助

本地搭建前后端项目时遇到对接问题:前端用VSCode的LiveServer部署(解决图片/模块加载的CORS问题),后端基于XAMPP,文件放在服务器目录。当前端提交登录表单,通过AJAX请求http://localhost/web/back/public/login时,接口返回空文件。为排查问题,在LoginController中添加了测试函数hola(),但该函数未被触发,说明请求根本没到控制器。

前端请求代码(login.js)

$(document).ready(function() {
    $('#login-form').submit(function(event) {
      event.preventDefault(); 
      const username = $('#email').val();
      const password = $('#password').val();
      // 发送登录AJAX请求
      $.ajax({
        url: 'http://localhost/web/back/public/login',
        method: 'POST',
        dataType: 'json',
        contentType: 'application/json',
        error: function(error) {
          console.error(error);
        }
      });
    });
  });

注:原代码中error回调存在语法缺失,已补全error: function(error)部分

后端入口文件(Index.php)

<?php
include('../app/routes/Login.php');
foreach ($routes as $url => $route) {
  $method = $route[0];
  $controller = $route[1];
  $action = $route[2];

  error_log("处理路由: $url");
  error_log("请求方法: " . $_SERVER['REQUEST_METHOD']);
  error_log("请求URI: " . $_SERVER['REQUEST_URI']);

  if ($_SERVER['REQUEST_METHOD'] === $method && preg_match('#^'.$url.'$#', $_SERVER['REQUEST_URI'])) {
    error_log("匹配到路由,调用控制器: $controller 方法: $action");

    $controller = new $controller();
    $controller->$action();
    break;
  }
}
?>

后端路由文件(Login.php)

<?php
use back\app\controllers\LoginController;

$routes = [
  '/login' => ['POST', LoginController::class, 'login'],
  '/logout' => ['POST', LoginController::class, 'logout']
];
?>

后端控制器文件(LoginController.php)

<?php
session_start(); 
require_once '../../tools/connection.php';

// 错误:类定义外调用$this->hola(),此处代码会直接报错中断执行
// $this->hola();
class LoginController
{
    function hola(){
        echo("HOLA");
    }
    public function login()
    {
        $data = json_decode(file_get_contents('php://input'), true);
        $username = $data['username'];
        $password = $data['password'];

        $authResult = $this->authenticate($username, $password);
        // 修正:authenticate返回数组而非布尔值,需判断是否为错误结果
        if (!isset($authResult['error'])) {
            session_start();
            $_SESSION['logged_in'] = true;
            $_SESSION['username'] = $username;

            $response = [
                'success' => true,
                'message' => '登录成功'
            ];
            header('Content-Type: application/json');
            echo json_encode($response);
        } else {
            $response = [
                'success' => false,
                'message' => $authResult['error']
            ];
            header('Content-Type: application/json');
            http_response_code($authResult['code']);
            echo json_encode($response);
        }
    }

    public function logout()
    {
        // 关闭会话
        session_start();
        session_destroy();

        $response = [
            'success' => true,
            'message' => '注销成功'
        ];
        header('Content-Type: application/json');
        echo json_encode($response);
    }
   
    private function authenticate(string $username, string $password)
    {
        if (empty($username) || empty($password)) {
            return ['error' => '用户名或密码为空', 'code' => 401];
        }

        $conn = connect();

        $sql = "SELECT p.*, CASE 
                WHEN a.IdPersona IS NOT NULL THEN 'Administrador' 
                WHEN t.IdPersona IS NOT NULL THEN 'Tutor' 
                WHEN al.IdPersona IS NOT NULL THEN 'Alumno' 
                ELSE NULL 
            END AS Rol
            FROM Persona p
            LEFT JOIN Administrador a ON a.IdPersona = p.IdPersona
            LEFT JOIN Tutor t ON t.IdPersona = p.IdPersona
            LEFT JOIN Alumno al ON al.IdPersona = p.IdPersona
            WHERE p.CorreoElectronico = :username";

        $stmt = $conn->prepare($sql);
        $stmt->bindParam(':username', $username);

        $stmt->execute();

        $result = $stmt->fetch();

        if (!$result || $result['Password'] !== $password) {
            return ['error' => '用户名或密码错误', 'code' => 401];
        }

        switch ($result['Rol']) {
            case 'Administrador':
                $userType = 'administrador';
                break;
            case 'Tutor':
                $userType = 'tutor';
                break;
            case 'Alumno':
                $userType = 'alumno';
                break;
            default:
                return ['error' => '用户类型不存在', 'code' => 401];
        }

        return [
            'id' => $result['IdPersona'],
            'nombre' => $result['Nombre'],
            'apellido' => $result['Apellido'],
            'email' => $result['CorreoElectronico'],
            'rol' => $userType
        ];
    }
}

注:原代码存在两处致命错误:1. 类定义外部调用$this->hola(),会直接触发Fatal Error导致脚本中断;2. login方法中错误将authenticate的数组返回值当作布尔值判断

异常截图

  • 浏览器控制台错误:
    浏览器控制台错误
  • Preflight请求:
    Preflight请求
  • XHR请求:
    XHR请求

排查解决步骤

  1. 修复控制器致命错误:删除LoginController.php中类定义外的$this->hola();代码,该语句在类实例化前调用,直接导致脚本崩溃,无法处理请求。
  2. 修正登录逻辑判断:authenticate方法返回的是数组而非布尔值,需修改login方法中的判断逻辑,检查返回结果是否包含error字段。
  3. 检查路由匹配:查看XAMPP的错误日志(xampp/apache/logs/error.log),确认Index.php中输出的error_log内容,判断请求URI是否与路由/login匹配。当前请求URI是/web/back/public/login,而路由定义的是/login,正则匹配#^/login$#无法匹配完整URI,需调整路由规则为#^/web/back/public/login$#或者修改路由定义为相对路径。
  4. 处理CORS问题:从Preflight请求截图看,需在后端添加CORS响应头,允许前端域名的跨域请求。可在Index.php顶部添加:
header("Access-Control-Allow-Origin: *"); // 生产环境建议指定具体域名
header("Access-Control-Allow-Methods: POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
// 处理OPTIONS预请求
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    exit(0);
}
  1. 补全AJAX请求数据:前端AJAX未发送username和password数据,需添加data参数:
data: JSON.stringify({ username: username, password: password }),

内容的提问来源于stack exchange,提问作者Ivan Martin Blanco

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 13:15:03