Xử lý lỗi Cross-Origin Resource Sharing (CORS) với PHP và AJAX

Khi phát triển ứng dụng web, bạn thường gặp tình trạng trình duyệt chặn các yêu cầu AJAX nếu tên miền của phía gửi (client) và phía nhận (server) khác nhau. Đây được gọi là chính sách đồng nguồn (Same-Origin Policy). Để giải quyết vấn đề này, chúng ta cần cấu hình CORS (Cross-Origin Resource Sharing) trên phía server bằng PHP.

Lỗi CORS phổ biến

Giả sử trang web của bạn chạy tại domain-a.com và bạn muốn gửi yêu cầu tới api-server.com. Nếu server chưa được cấu hình, trình duyệt sẽ báo lỗi:

XMLHttpRequest cannot load http://api-server.com/process.php. No 'Access-Control-Allow-Origin' header is present on the requested resource.

Cấu hình cơ bản phía Server

Cách nhanh nhất để cho phép các yêu cầu truy cập từ bên ngoài là bổ sung các header phản hồi trong tệp PHP của bạn:

// Cho phép mọi nguồn truy cập (không khuyến khích cho production)
header('Access-Control-Allow-Origin: *');

// Chỉ định các phương thức HTTP được phép
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');

// Cấu hình các Header tùy chỉnh được chấp nhận
header('Access-Control-Allow-Headers: x-requested-with, content-type');

Ví dụ triển khai chi tiết

Dưới đây là ví dụ về cách gửi dữ liệu từ Client và xử lý tại Server.

1. Mã nguồn phía Client (index.html)

Sử dụng jQuery để gửi một yêu cầu POST tới server khác tên miền:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Test CORS AJAX</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
    <div id="result-display"></div>

    <script type="text/javascript">
        $.post("http://api-server.com/process.php", { 
            username: "tech_user", 
            action: "get_profile" 
        })
        .done(function(response) {
            $("#result-display").html("User: " + response.username + " - Action: " + response.action);
        })
        .fail(function() {
            alert("Lỗi kết nối liên miền!");
        });
    </script>
</body>
</html>

2. Mã nguồn phía Server (process.php)

Tệp PHP xử lý dữ liệu và trả về JSON kèm theo cấu hình CORS:

<?php
// Lấy dữ liệu từ yêu cầu POST
$payload = [
    'username' => $_POST['username'] ?? 'unknown',
    'action'   => $_POST['action'] ?? 'none',
    'status'   => 'success'
];

// Thiết lập header trả về định dạng JSON
header('Content-Type: application/json; charset=utf-8');

// Cấu hình CORS
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET');
header('Access-Control-Allow-Headers: Content-Type, X-Requested-With');

echo json_encode($payload);
?>

Xử lý cho phép nhiều tên miền cụ thể

Việc sử dụng dấu sao (*) cho Access-Control-Allow-Origin có thể gây rủi ro bảo mật. Nếu bạn chỉ muốn cho phép một danh sách các tên miền nhất định, hãy sử dụng logic sau:

<?php
$requestOrigin = $_SERVER['HTTP_ORIGIN'] ?? '';

// Danh sách các domain được phép truy cập
$whiteList = [
    'http://my-app.com',
    'https://secure-site.vn',
    'http://localhost:8080'
];

if (in_array($requestOrigin, $whiteList)) {
    header('Access-Control-Allow-Origin: ' . $requestOrigin);
    header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
    header('Access-Control-Allow-Headers: Content-Type, X-Requested-With');
}

// Logic xử lý nghiệp vụ tiếp theo...
$data = ['info' => 'Dữ liệu bảo mật'];
echo json_encode($data);
?>

Bằng cách kiểm tra $_SERVER['HTTP_ORIGIN'], bạn có thể kiểm soát chặt chẽ những ứng dụng nào có quyền tương tác với API của mình, từ đó nâng cao tính bảo mật cho hệ thống.

Thẻ: php ajax CORS web-security HTTP-Headers

Đăng vào ngày 23 tháng 9 lúc 07:17