owned this note
owned this note
Published
Linked with GitHub
# CORS跨域問題
## 前端解決版本
### fetch
使用Fetch API:Fetch API是現代瀏覽器提供的一種用於發送網絡請求的接口。它内置了對CORS的支持。
限制:如果目標資源沒有設置CORS標頭,會導致瀏覽器阻止跨域請求的情況發生。
#### 未使用令牌
```javascript=
async function opendata() {
try {
const response = await fetch('https://od.moi.gov.tw/api/v1/rest/datastore/A01010000C-002150-013');
const data = await response.json();
console.log(data);
} catch (error) {
console.log(error);
}
}
```
### 使用令牌
```javascript
async function fetchData() {
try {
// your_token_here:請設置為實際令牌值
const token = 'your_token_here';
const response = await fetch('https://api.example.com/api-endpoint', {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
const data = await response.json();
console.log(data); // 處理 API 回傳的資料
} catch (error) {
console.error(error); // 處理錯誤
}
}
fetchData();
```
## 後端解決版本(PHP)
* 前端發請求
```javascript
async function opendata(){
try{
const response = await axios.post(`${API_URL}get_p03_opendata.php`)
console.log(response.data)
} catch (error){
console.log(error)
}
}
```
* 後端PHP檔
### 不使用令牌
```php=
// 跨域連線
// 建立一個 Express application 物件
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: GET, POST");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
// 目標API的URL
$targetUrl = 'https://od.moi.gov.tw/api/v1/rest/datastore/A01010000C-002150-013';
//判斷所使用的瀏覽器切換不同的User-Agen
function getUserAgent() {
$userAgent = $_SERVER['HTTP_USER_AGENT'];
if (strpos($userAgent, 'Chrome') !== false) {
// Chrome 瀏覽器
return 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.9999.999 Safari/537.36';
} else if (strpos($userAgent, 'Firefox') !== false) {
// Firefox 瀏覽器
return 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0';
} else if (strpos($userAgent, 'Safari') !== false) {
// Safari 瀏覽器
return 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15';
} else if (strpos($userAgent, 'Edge') !== false) {
// Microsoft Edge 浏览器
return 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.9999.999 Safari/537.36 Edge/99.0.999.999';
} else {
// 默認情況下使用一個常見瀏覽器的 User-Agent
return 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.9999.999 Safari/537.36';
}
}
// 使用獲取的 User-Agent 發送請求
$options = [
'http' => [
'method' => 'GET',
'header' => getUserAgent(),
],
];
//發送請求
$context = stream_context_create($options);
$response = file_get_contents($targetUrl, false, $context);
// 將得到的api回傳給前端
echo $response;
```
:::spoiler {state="open"} 註解
* `$_SERVER['HTTP_USER_AGENT']`:獲取瀏覽器相關參數
* `strpos()`:用於在字串中查找字符,併法回第一個匹配的位置。
* `User-Agent`:告訴服務器發送請求的客戶端的類型和版本信息。
> 常見的User-Agent:
> - Chrome:
**`'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.9999.999 Safari/537.36'`**
> - Firefox:
**`'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0'`**
> - Safari:
**`'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15'`**
> - Edge:
**`'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.9999.999 Safari/537.36 Edge/99.0.999.999'`**
* `stream_context_create()`:用於file_get_contents()、fopen()等函數傳遞額外的選項和參數
* `file_get_contents()`:函數在請求時會應用上下文資源中定義的選項和參數。這允許自定義請求,例如請求標頭、代理、超時時間等。
* 補充:。請求標頭是 HTTP 請求中包含的元信息,它包含了用於描述請求的各種屬性和參數,通常指的是 HTTP 請求中的標頭字段,用於描述請求的相關訊息,例如 User-Agent、Content-Type、Authorization 等。
:::
### 需要令牌
限制:如果目標資源有設定令牌,需要在PHP檔案中添加令牌訊息。
```php=
// 跨域連線
// 建立一個 Express application 物件
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: GET, POST");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
// 目標API的URL
$targetUrl = 'https://od.moi.gov.tw/api/v1/rest/datastore/A01010000C-002150-013';
// 獲得前端請求的方式與數據
$method = $_SERVER['REQUEST_METHOD'];
$data = file_get_contents('php://input');
// 建立一個curl
$curl = curl_init();
//設置請求的自訂標頭,令牌訊息也設定在這
$headers = [
//your_token_here:請設置為實際令牌值
'Authorization: Bearer your_token_here',
'Content-Type: application/json',
// 其他標頭設置
];
// 設置curl選項
curl_setopt($curl, CURLOPT_URL, $targetUrl);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_MAXREDIRS, 5);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
// 根据前端發縙的請求方法設置cURL選項
if ($method === 'POST') {
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
// 執行cURL
$response = curl_exec($curl);
// 檢查是否有發生錯誤
if ($response === false) {
$error = curl_error($curl);
echo 'cURL Error: ' . $error;
}
// 關閉cURL
curl_close($curl);
// 將得到的api回傳給前端
echo $response;
```
:::spoiler {state="open"} 註解
- **`curl_setopt()`:** 函數是用於設置 cURL 請求的選項。
- **`CURLOPT_URL`:** cURL 函數提供的一個選項常數,用於指定要請求的 URL。
- **`CURLOPT_RETURNTRANSFER`:** 是一個 cURL 選項常數,它指示 cURL 函數將請求的結果作為字串返回,而不是直接輸出到標準輸出流。這樣可以方便在程式中捕獲和處理請求的結果。
- 備註:通過將第三個參數設置為 true,表示開啟 CURLOPT_RETURNTRANSFER 選項。這意味著 cURL 函數在發送請求後,將返回請求的結果作為字串。
- **`CURLOPT_HEADER`:** 是一個 cURL 選項常數,它指示 cURL 函數在請求中是否包含標頭信息。
- 通過將第三個參數設置為 **`false`**,表示關閉 **`CURLOPT_HEADER`** 選項,即在請求中不包含標頭信息。
- **`CURLOPT_FOLLOWLOCATION`:**:用於設置 cURL 請求是否要自動跟隨重定向。
- 備註:當設置為 **`true`** 時,cURL 將自動跟隨伺服器返回的重定向,從而完成整個請求過程。如果目標 URL 返回重定向響應(例如 301 或 302 狀態碼),cURL 將自動重新發送請求到新的位置。
- 注意事項:為了避免無限重定向的情況,cURL 限制了最大重定向次數。如果重定向次數超過限制,則請求將被終止並返回錯誤
- **`CURLOPT_MAXREDIRS`:** 設置最大重定向次數,如果超過這個數量,請求將被終止並返回錯誤。你可以根據需要調整最大重定向次數。
- **`CURLOPT_HTTPHEADER`:** 是用於設置 cURL 請求的自訂標頭(HTTP headers)。
- **`curl_exec($curl)`:** 函數用於獲取請求結果,該函數會返回一個包含請求結果的字串。
:::
###### 持續更新中!
###### 以上為自學中的筆記如有錯誤,懇請留言指正,感謝!