การตั้งค่า CORS Headers ใน PHP
จากบทที่แล้ว เราได้เรียนรู้เกี่ยวกับ CORS (Cross-Origin Resource Sharing) และความสำคัญของมันในการอนุญาตให้เว็บไซต์จากโดเมนหนึ่งสามารถเข้าถึง Resources จากอีกโดเมนหนึ่งได้ ในบทนี้ เราจะมาเรียนรู้วิธีการตั้งค่า CORS Headers ใน PHP เพื่อให้ API ของเราสามารถถูกเรียกใช้งานจาก Front-end ที่รันอยู่บนโดเมนที่แตกต่างกันได้
CORS Headers คืออะไร?
CORS Headers คือ HTTP Headers ที่ Server ส่งกลับมาพร้อมกับ Response เพื่อบอก Browser ว่าอนุญาตให้ Cross-Origin Request จากโดเมนใดบ้าง Headers ที่สำคัญมีดังนี้:
- Access-Control-Allow-Origin: ระบุโดเมนที่ได้รับอนุญาตให้เข้าถึง Resources ของ Server ได้
- Access-Control-Allow-Methods: ระบุ HTTP Methods (GET, POST, PUT, DELETE, OPTIONS) ที่ได้รับอนุญาต
- Access-Control-Allow-Headers: ระบุ HTTP Headers ที่ Client สามารถส่งมาใน Request ได้
การตั้งค่า Access-Control-Allow-Origin
Access-Control-Allow-Origin เป็น Header ที่สำคัญที่สุด เพราะเป็นตัวกำหนดว่าโดเมนใดบ้างที่ได้รับอนุญาตให้เข้าถึง API ของเราได้ มีสองค่าหลักๆ ที่เราสามารถใช้ได้:
*: อนุญาตให้ทุกโดเมนเข้าถึง API ของเราได้ (ไม่แนะนำให้ใช้ใน Production เพราะไม่ปลอดภัย)[domain]: อนุญาตให้เฉพาะโดเมนที่ระบุเท่านั้น เช่นhttps://example.com
ตัวอย่าง: การอนุญาตให้ทุกโดเมนเข้าถึง API ของเรา
<?php
header("Access-Control-Allow-Origin: *");
// โค้ด API ของคุณ
echo json_encode(["message" => "Hello from API"]);
?>
ตัวอย่าง: การอนุญาตให้เฉพาะ https://example.com เข้าถึง API ของเรา
<?php
header("Access-Control-Allow-Origin: https://example.com");
// โค้ด API ของคุณ
echo json_encode(["message" => "Hello from API"]);
?>
ข้อควรระวัง: การใช้ * ใน Access-Control-Allow-Origin จะไม่สามารถใช้ร่วมกับ Access-Control-Allow-Credentials: true ได้ หากต้องการส่ง Cookies หรือ Authorization Headers ข้ามโดเมน จะต้องระบุโดเมนที่ต้องการอนุญาตอย่างชัดเจน
การตั้งค่า Access-Control-Allow-Methods
Access-Control-Allow-Methods เป็น Header ที่ระบุ HTTP Methods ที่ได้รับอนุญาตให้ใช้ในการ Request ไปยัง API ของเรา โดยทั่วไปแล้ว เราจะอนุญาตให้ใช้ Methods ที่ API ของเรารองรับ เช่น GET, POST, PUT, DELETE, และ OPTIONS
ตัวอย่าง: การอนุญาตให้ใช้ GET, POST, PUT, และ DELETE Methods
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
// โค้ด API ของคุณ
echo json_encode(["message" => "Hello from API"]);
?>
สำคัญ: Browser จะส่ง OPTIONS Request มาก่อน (Preflight Request) หากมีการใช้ Methods อื่นๆ นอกเหนือจาก GET หรือ POST ที่มี Content-Type เป็น application/x-www-form-urlencoded, multipart/form-data, หรือ text/plain ดังนั้น เราจึงต้องรองรับ OPTIONS Method ใน API ของเราด้วย
การตั้งค่า Access-Control-Allow-Headers
Access-Control-Allow-Headers เป็น Header ที่ระบุ HTTP Headers ที่ Client สามารถส่งมาใน Request ได้ หาก Client พยายามส่ง Headers ที่ไม่ได้ระบุไว้ใน Access-Control-Allow-Headers Browser จะทำการ Block Request นั้น
ตัวอย่าง: การอนุญาตให้ส่ง Content-Type, Authorization, และ X-Requested-With Headers
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
// โค้ด API ของคุณ
echo json_encode(["message" => "Hello from API"]);
?>
ข้อควรจำ: หาก Client ต้องการส่ง Custom Headers เช่น X-Custom-Header จะต้องระบุ Header นั้นใน Access-Control-Allow-Headers ด้วย
การจัดการ Preflight Request (OPTIONS Method)
อย่างที่กล่าวไปข้างต้น Browser จะส่ง OPTIONS Request มาก่อน (Preflight Request) หากมีการใช้ Methods อื่นๆ นอกเหนือจาก GET หรือ POST ที่มี Content-Type เป็น application/x-www-form-urlencoded, multipart/form-data, หรือ text/plain เราจึงต้องรองรับ OPTIONS Method ใน API ของเราด้วย
ตัวอย่าง: การจัดการ OPTIONS Request
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
http_response_code(200);
exit;
}
// โค้ด API ของคุณ
echo json_encode(["message" => "Hello from API"]);
?>
ในตัวอย่างนี้ เราตรวจสอบว่า Request Method เป็น OPTIONS หรือไม่ หากเป็น OPTIONS เราจะส่ง HTTP Status Code 200 OK กลับไปโดยไม่ต้องทำอะไรเพิ่มเติม
กรณีใช้งานจริง
สมมติว่าเรามี Front-end ที่รันอยู่ที่ https://frontend.example.com และ API ที่รันอยู่ที่ https://api.example.com เราต้องการให้ Front-end สามารถเรียก API ได้โดยไม่ติดปัญหา CORS เราสามารถตั้งค่า CORS Headers ใน API ได้ดังนี้:
<?php
header("Access-Control-Allow-Origin: https://frontend.example.com");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
header("Access-Control-Allow-Credentials: true"); // หากต้องการส่ง Cookies
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
http_response_code(200);
exit;
}
// โค้ด API ของคุณ
echo json_encode(["message" => "Hello from API"]);
?>
ในตัวอย่างนี้ เราอนุญาตให้เฉพาะ https://frontend.example.com เข้าถึง API ของเราได้ และอนุญาตให้ใช้ GET, POST, PUT, DELETE, และ OPTIONS Methods นอกจากนี้ เรายังอนุญาตให้ส่ง Content-Type, Authorization, และ X-Requested-With Headers ได้ หากต้องการส่ง Cookies ข้ามโดเมน เราต้องตั้งค่า Access-Control-Allow-Credentials: true ทั้งใน Server และ Client (Front-end)
ข้อผิดพลาดที่พบบ่อย
- CORS Error ใน Browser: ตรวจสอบว่าได้ตั้งค่า CORS Headers อย่างถูกต้องใน Server และตรวจสอบว่าโดเมนของ Front-end ได้รับอนุญาต
- การใช้
*ใน Production: ไม่แนะนำให้ใช้*ในAccess-Control-Allow-Originใน Production เพราะไม่ปลอดภัย ควรระบุโดเมนที่ต้องการอนุญาตอย่างชัดเจน - การลืมจัดการ
OPTIONSRequest: หากใช้ Methods อื่นๆ นอกเหนือจากGETหรือPOSTที่มี Content-Type ที่กำหนด ต้องจัดการOPTIONSRequest ด้วย - การไม่ระบุ Headers ที่ Client ส่ง: หาก Client พยายามส่ง Headers ที่ไม่ได้ระบุไว้ใน
Access-Control-Allow-HeadersBrowser จะทำการ Block Request นั้น
สรุป
การตั้งค่า CORS Headers ใน PHP เป็นสิ่งจำเป็นเพื่อให้ API ของเราสามารถถูกเรียกใช้งานจาก Front-end ที่รันอยู่บนโดเมนที่แตกต่างกันได้ เราต้องเข้าใจความหมายของ Access-Control-Allow-Origin, Access-Control-Allow-Methods, และ Access-Control-Allow-Headers และตั้งค่าให้ถูกต้องตามความต้องการของ API ของเรา นอกจากนี้ เรายังต้องจัดการ OPTIONS Request อย่างถูกต้องด้วย
ในบทถัดไป เราจะมาเรียนรู้เกี่ยวกับการจัดการ Version ของ API ซึ่งเป็นสิ่งสำคัญในการรักษาความเข้ากันได้กับ Client รุ่นเก่าๆ