API 開發

API 開發中的 URL 編碼最佳實踐

2026-03-13 閱讀時間約 10 分鐘 API、Query String、REST

為什麼 API 開發者需要了解 URL 編碼?

在 RESTful API 開發中,URL 編碼是一個看似簡單卻常常出錯的環節。錯誤的 URL 編碼處理可能導致:參數值被截斷、資料解析失敗、雙重編碼導致亂碼、SQL injection 風險,以及跨語言 API 整合問題。

本文將以實際程式碼範例,系統性介紹 API 開發中 URL 編碼的正確做法。

Query String 的正確處理方式

Query string 是 URL 中 ? 之後的部分,格式為 key=value&key2=value2。每個 key 和 value 都必須分別進行 URL 編碼。

常見錯誤:直接拼接字串
const url = '/api/search?q=' + userInput;
若 userInput 含有 &、=、# 等字元,會破壞 URL 結構。

正確做法:使用 encodeURIComponent 或 URLSearchParams
const url = '/api/search?q=' + encodeURIComponent(userInput);
或使用 URLSearchParams API(更推薦)。

JavaScript / TypeScript(前端與 Node.js)

// 方法一:URLSearchParams(推薦)
const params = new URLSearchParams({
  q: '台北 咖啡店',
  category: 'food&drink',
  page: '1'
});
const url = `/api/search?${params.toString()}`;
// → /api/search?q=%E5%8F%B0%E5%8C%97+%E5%92%96%E5%95%A1%E5%BA%97&category=food%26drink&page=1

// 方法二:手動編碼每個參數值
const url2 = `/api/search?q=${encodeURIComponent('台北 咖啡店')}&category=${encodeURIComponent('food&drink')}`;

// 解析 URL 參數(後端 / Node.js)
const { URL } = require('url');
const reqUrl = new URL(req.url, 'http://localhost');
const q = reqUrl.searchParams.get('q');
// 自動解碼,直接得到 '台北 咖啡店'

Python(requests 函式庫)

import requests

# requests 函式庫自動處理 URL 編碼
response = requests.get(
    'https://api.example.com/search',
    params={
        'q': '台北 咖啡店',
        'category': 'food&drink',
        'page': 1
    }
)
# 實際發送:/search?q=%E5%8F%B0%E5%8C%97+%E5%92%96%E5%95%A1%E5%BA%97&category=food%26drink&page=1

# Flask 後端接收(自動解碼)
from flask import request
q = request.args.get('q')  # → '台北 咖啡店'(已自動解碼)

PHP

<?php
// 建構 query string
$params = http_build_query([
    'q' => '台北 咖啡店',
    'category' => 'food&drink',
    'page' => 1
]);
$url = "https://api.example.com/search?" . $params;
// → https://api.example.com/search?q=%E5%8F%B0%E5%8C%97+%E5%92%96%E5%95%A1%E5%BA%97&...

// 接收($_GET 自動解碼)
$q = $_GET['q']; // → '台北 咖啡店'
?>

Java(Spring Boot)

// 發送請求(使用 UriComponentsBuilder)
UriComponents uriComponents = UriComponentsBuilder
    .fromUriString("https://api.example.com/search")
    .queryParam("q", "台北 咖啡店")
    .queryParam("category", "food&drink")
    .build()
    .encode();  // 自動編碼

// Spring MVC 接收
@GetMapping("/search")
public ResponseEntity<?> search(@RequestParam String q) {
    // q 已自動解碼,直接使用
    return ResponseEntity.ok(searchService.search(q));
}

雙重編碼問題(Double Encoding)

雙重編碼是 API 開發中最常見的 URL 編碼問題。當某個元件對已編碼的字串再次編碼時就會發生:

// 錯誤:雙重編碼
const value = '你好';
const encoded = encodeURIComponent(value); // → '%E4%BD%A0%E5%A5%BD'
const doubleEncoded = encodeURIComponent(encoded); // → '%25E4%25BD%25A0%25E5%25A5%25BD'
// % 本身被編碼為 %25,伺服器收到後解碼一次,還是亂碼!

// 正確:只對原始值編碼一次
const url = `/api/greet?name=${encodeURIComponent('你好')}`;
// → /api/greet?name=%E4%BD%A0%E5%A5%BD

常見的雙重編碼場景
• 後端接收到參數後,直接放入 SQL 查詢或另一個 HTTP 請求的 URL 時,未先解碼就再次編碼。
• nginx / Apache 的 URL 重寫規則已編碼,但應用層再次編碼。
• 使用 axios 的 params 選項,同時又手動呼叫了 encodeURIComponent。

各場景 URL 編碼選擇指南

場景推薦方法說明
Query string 參數值 encodeURIComponent() 最嚴格,連 &、=、+ 都編碼
完整 URL encodeURI() 保留 URL 結構字元
建構多個參數 URLSearchParams 自動處理全部參數的編碼
HTML form 資料 瀏覽器自動處理 空格編碼為 +,其他用 %XX
axios params 選項 直接傳物件 axios 自動編碼,勿重複呼叫 encode
Python requests params 直接傳 dict requests 自動編碼

空格的編碼:%20 vs +

空格有兩種編碼方式,使用場景不同:

現代 API 建議統一使用 %20(encodeURIComponent),避免 + 在不同場景下的解讀歧義。若必須相容 HTML form 格式,確認後端解碼方式。

Axios 的 URL 編碼處理

import axios from 'axios';

// 正確:使用 params 物件,axios 自動編碼
axios.get('/api/search', {
  params: {
    q: '台北 咖啡店',
    category: 'food&drink'
  }
});
// 實際請求:/api/search?q=%E5%8F%B0%E5%8C%97%20%E5%92%96%E5%95%A1%E5%BA%97&category=food%26drink

// 錯誤:手動拼接 + 使用 params(雙重編碼)
axios.get('/api/search', {
  params: {
    q: encodeURIComponent('台北 咖啡店')  // 已編碼,axios 再次編碼 → 雙重編碼!
  }
});

後端 URL 解碼的正確時機

大多數現代框架(Express、Spring、Django、Laravel)都會在解析路由參數和 query string 時自動解碼,開發者不需要手動呼叫解碼函式。

不要在已自動解碼的框架中再次手動解碼
如果框架已經解碼,再次呼叫 decodeURIComponent(req.query.q) 可能會在原始值含有 % 字元時拋出錯誤(URIError: malformed URI sequence)。

驗證您的 URL 編碼結果

使用我們的免費工具即時測試 URL 編碼,確保 API 參數正確無誤。

前往工具頁面