JavaScript
FetchAPI
CORS
PHP
example.js
fetch('http://example.url/example/route', {
method: 'POST',
credentials: 'include',
headers: new Headers({
'Custom-Header': encodeURIComponent('A custom message'), // 可傳輸非 ISO-8859-1 字元
'Custom-Cookie': document.cookie
})
})
.then(response => {
if (response.ok) return response.json();
throw new Error(`${response.url} (${response.statusText})`);
})
.then(async data => {
console.log(data);
// 將後端回應的 Base64 資料解碼再轉回 UTF-8
let message = decodeURIComponent(window.atob(data.message));
console.log(message);
})
.catch(error => {
console.warn(error);
});
http://example.url/example/route
<?php
# 白名單
$allowedHost = [
'61.62.63.64',
'101.102.103.104',
'185.186.187.188'
];
# 取得請求發送者的 IP
$clientIP = (function()
{
$ip = null;
if (isset($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] !== '')
{
$ip = $_SERVER['HTTP_CLIENT_IP'];
}
else if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] !== '')
{
$ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
}
else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] !== '')
{
$ip = $_SERVER['REMOTE_ADDR'];
}
return trim($ip);
})();
# 帶微秒的請求時間
$requestData = (function()
{
$time = explode('.', $_SERVER['REQUEST_TIME_FLOAT']);
$date = date('Y-m-d H:i:s', $time[0]);
return "{$date}.{$time[1]}";
})();
# 限定接受的 HTTP 方法為 OPTIONS(預檢請求)及 POST(自定義),其他方法回 404
switch ($_SERVER['REQUEST_METHOD'])
{
case 'OPTIONS':
case 'POST':
{
# 宣告 CORS 預檢請求(Preflight Request)所需要的 header
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS')
{
header("Access-Control-Request-Method: GET, POST, PUT, PATCH, DELETE, OPTIONS");
header('Access-Control-Allow-Headers: Content-Type, Custom-Header, Custom-Cookie');
}
# 允許 CORS 認證
header('Access-Control-Allow-Credentials: true');
# 連入 IP 不在白名單內,返回 401
if (!in_array($clientIP, $allowedHost))
{
header("{$_SERVER['SERVER_PROTOCOL']} 401 Unauthorized");
exit;
}
# 請求來自瀏覽器時,在回應 header 中加入允許來源
if (isset($_SERVER['HTTP_ORIGIN']))
{
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
}
# 預檢 OPTIONS 動作完畢,跳出 switch case
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') break;
# 回應資料陣列
$data = [];
# 請求 header 中有 Custom-Header 時,將其值 base64 編碼處理後加入為回應資料的 message 欄位
if (isset($_SERVER['HTTP_CUSTOM_HEADER']))
{
$data['message'] = base64_encode($_SERVER['HTTP_CUSTOM_HEADER']);
}
# 取得請求 header 中帶的 Custom-Cookie
$customCookie = [];
if (isset($_SERVER['HTTP_CUSTOM_COOKIE']))
{
$customCookiePair = explode(';', $_SERVER['HTTP_CUSTOM_COOKIE']);
foreach ($customCookiePair as $cookiePair)
{
$cookieSlice = explode('=', $cookiePair);
if (trim($cookieSlice[0]) !== '')
{
$customCookie[trim($cookieSlice[0])] = trim($cookieSlice[1]);
}
}
}
$data['customCookie'] = $customCookie;
# 通知瀏覽器建立 cookie(須指定 SameSite=None; Secure 選項)
setcookie('lastAccessDate', $requestDate, [
'samesite' => 'None',
'secure' => true
]);
# 將 SERVER 資訊加入回應資料以便檢視
$data = array_merge($data, ['server' => $_SERVER]);
# 將 COOKIE 資訊加入回應資料以便檢視
$data = array_merge($data, ['cookie' => $_COOKIE]);
header('Content-Type: application/json');
echo json_encode($data, 320);
break;
}
default:
header("{$_SERVER['SERVER_PROTOCOL']} 404 Not Found");
break;
}
exit;
Kubernetes in Docker
Mar 17, 2025參考資料 實測經驗提供:Timmy Chao 還原資料庫的前置作業 | 積沙成塔 - 點部落 步驟 設資料庫名稱為 agroup,BAK 檔名為 Backup.bak 把 BAK 檔放進 SQL Server volume 可讀取的地方 以下設我們存放 BAK 檔的路徑為 /var/opt/mssql/data/Backup.bak
Jun 8, 2022表驅動法(Table-driven Methods)階梯訪問(Stair-step Access)的一個簡單的 PHP 範例。 <?php $x = 13; $numberNodes = [ 1, 5, 10, 16, 21 ]; $numberTable = [ '0', '1', '2', '3', '4', '5' ]; $numberLevel = 0;
Sep 9, 2021or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up