2025年6月12日 星期四

如何防止測試網站被 Google 搜尋引擎收錄?完整指南

在網站開發過程中,通常會有測試環境(例如 staging.example.com),用來驗證功能、佈署流程或設計樣式。但你絕對不希望這些測試網站被 Google 收錄,否則可能會影響 SEO 或洩漏未公開資訊。

這篇文章將完整介紹幾種有效的方式,防止測試網站被搜尋引擎(如 Google)收錄與索引,並提供實作範例,讓你輕鬆上手。

為什麼測試網站會被收錄?

Googlebot(Google 的爬蟲)會自動搜尋網路上的網站,只要:

  • 網站能連上
  • 沒有阻擋爬蟲
  • 有外部連結指向

那麼就可能被收錄。即使沒有主動提交,只要一個連結出現在別的頁面,就可能進入 Google 索引。

方法一:使用 robots.txt 阻擋爬蟲

在網站根目錄新增 robots.txt 檔案,加入以下內容:

User-agent: *
Disallow: /

這代表對所有搜尋引擎「禁止抓取整個網站」。

⚠️ 注意:
robots.txt 僅告訴搜尋引擎「不要抓」,但它 不會阻止網址被收錄。如果某個網址被外部連結指向,網址還是可能出現在搜尋結果中。

方法二:使用 <meta name="robots"> 阻擋索引

在 HTML 頁面的 <head> 區塊加入:

<meta name="robots" content="noindex, nofollow">

這告訴搜尋引擎「不要索引這個頁面,也不要追蹤裡面的連結」。Google 必須能成功抓到頁面,才能讀取這段設定。

方法三:用 HTTP Header 傳送 X-Robots-Tag(適用 Nginx)

如果你使用 Nginx,也可以透過 HTTP header 傳送禁止收錄的資訊。

Nginx 設定範例(整站禁止收錄):

location / {
    add_header X-Robots-Tag "noindex, nofollow" always;
    proxy_pass http://backend;
}

使用 always 是為了讓所有狀態碼(不只是 200)都加上這個 header。

用 curl 驗證:

curl -I https://your-site.com

預期輸出:

X-Robots-Tag: noindex, nofollow

方法四:帳號密碼保護(最有效)

透過 HTTP Basic Auth 保護測試站,搜尋引擎無法登入,自然也無法索引。

Apache .htaccess 範例:

AuthType Basic
AuthName "Restricted"
AuthUserFile /var/www/.htpasswd
Require valid-user

Nginx Basic Auth 範例:

location / {
    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

這種方法最保險,Google 連抓都抓不到

附加提醒:Google Search Console 移除已收錄內容

  1. 前往 Google Search Console
  2. 使用「移除網址」工具
  3. 提交要移除的網址

方法總結

方法 可防止被收錄 可防止被抓取 備註
robots.txt 只是建議,可能仍被列出
<meta name="robots"> Google 要能抓到才有效
X-Robots-Tag 適用靜態檔、API
密碼保護 最安全有效

結語

建議:測試環境最好同時使用「密碼保護」與「noindex」設定,確保不被搜尋引擎收錄與解析,避免意外曝光未發佈內容。

2025年6月1日 星期日

C# 非同步背景任務完整攻略:async/await、ThreadPool、SemaphoreSlim 與協程並發控制(含範例)

在現代 C# 開發中,如何有效執行背景任務、限制併發數量、與 UI 協作已成為必備技能。本篇文章整理各種方式的特性、應用場景,並附上實用程式碼範例。

🧩 為何需要多種背景任務執行方式?

背景任務可避免 UI 卡頓、提升效能並允許多工操作。常見需求包括:

  • 執行不阻塞主線程(UI)
  • 控制同時併發的數量
  • 可 await 等待完成
  • 與 WinForms / WPF UI 結合

✅ 背景任務方式比較(含執行類型)

技術控制併發數支援 async/await適用場景UI 支援執行方式
BackgroundWorker舊式 WinForms/WPF 背景任務Thread
ThreadPool快速提交背景任務Thread
Task / Task.Run一般非同步任務Thread
Task + SemaphoreSlim控制併發數、IO 密集任務Thread + Coroutine
Parallel.ForEachCPU 密集型處理Thread
TPL Dataflow複雜資料管線與佇列Thread
async/await✅(手動限制)非同步 API / DB / IO 流程Coroutine

🧪 範例程式碼

1️⃣ BackgroundWorker

var worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
    Thread.Sleep(2000);
    e.Result = "任務完成";
};
worker.RunWorkerCompleted += (s, e) =>
{
    MessageBox.Show((string)e.Result);
};
worker.RunWorkerAsync();

2️⃣ ThreadPool

ThreadPool.QueueUserWorkItem(state =>
{
    Console.WriteLine("背景任務開始");
    Thread.Sleep(1000);
    Console.WriteLine("任務完成");
});

3️⃣ Task / Task.Run


await Task.Run(() =>
{
    Thread.Sleep(1000);
    Console.WriteLine("Task 執行完成");
});

4️⃣ Task + SemaphoreSlim(控制併發數)

var semaphore = new SemaphoreSlim(3);
var tasks = new List<Task>();

for (int i = 0; i < 10; i++)
{
    int index = i;
    tasks.Add(Task.Run(async () =>
    {
        await semaphore.WaitAsync();
        try
        {
            Console.WriteLine($"工作 {index} 開始");
            await Task.Delay(2000);
            Console.WriteLine($"工作 {index} 結束");
        }
        finally
        {
            semaphore.Release();
        }
    }));
}

await Task.WhenAll(tasks);

5️⃣ Parallel.ForEach

Parallel.ForEach(Enumerable.Range(0, 5), i =>
{
    Console.WriteLine($"執行任務 {i} - 線程 {Thread.CurrentThread.ManagedThreadId}");
    Thread.Sleep(1000);
});

6️⃣ TPL Dataflow

var block = new ActionBlock<int>(async i =>
{
    Console.WriteLine($"處理 {i}");
    await Task.Delay(500);
}, new ExecutionDataflowBlockOptions
{
    MaxDegreeOfParallelism = 3
});

foreach (var i in Enumerable.Range(0, 10))
{
    block.Post(i);
}

block.Complete();
await block.Completion;

📦 需安裝: System.Threading.Tasks.Dataflow

7️⃣ async/await Coroutine

async Task<string> DownloadAsync(string url)
{
    using var client = new HttpClient();
    var result = await client.GetStringAsync(url);
    return result;
}

var html = await DownloadAsync("https://example.com");
Console.WriteLine(html);

🧠 Thread vs Coroutine

類型說明
Thread作業系統層級,適合同步或 CPU 密集任務
Coroutine由 .NET 控制流程(Task + await),讓出執行緒等 IO

💡 小結

  • Taskasync/await 是現代開發主力
  • SemaphoreSlim 控制併發數
  • ⚠️ BackgroundWorker 僅建議用於舊 UI 專案

2025年5月31日 星期六

Python 非同步程式設計入門:async/await 與 asyncio 基本教學

隨著網路應用與 I/O 密集型工作越來越普遍,Python 的非同步程式設計變得非常重要。本篇文章將帶你了解 Python 中 async / await 的用法,並介紹 asyncio 模組的基本概念與範例。

什麼是非同步程式設計?

非同步程式設計讓你能夠在等待 I/O(像是網路請求、檔案讀寫)時,不會阻塞整個程式,而是把時間留給其他工作繼續執行,提高效率。

Python 的 async 與 await

  • async def:定義非同步函式(協程 coroutine)
  • await:等待一個協程或非同步任務完成

範例:定義與呼叫非同步函式

import asyncio

async def say_hello():
    print("Hello")
    await asyncio.sleep(1)  # 非同步等待 1 秒
    print("World")

asyncio.run(say_hello())

asyncio 模組簡介

Python 的 asyncio 是標準庫裡負責非同步事件循環的模組,主要用來調度與執行多個協程。

同時執行多個協程:asyncio.gather()

import asyncio

async def task(id, delay):
    print(f"Task {id} 開始")
    await asyncio.sleep(delay)
    print(f"Task {id} 結束")
    return id * 10

async def main():
    results = await asyncio.gather(
        task(1, 2),
        task(2, 1),
        task(3, 3),
    )
    print("結果:", results)

asyncio.run(main())

控制非同步併發數量(類似 ThreadPoolExecutor)

當你有一個參數列表,想非同步呼叫很多工作,但想限制同時執行的任務數量(例如同時最多 3 個),可以用 asyncio.Semaphore 來做到。

import asyncio

async def worker(sem, param):
    async with sem:  # 申請 Semaphore,限制同時併發數
        print(f"開始處理 {param}")
        await asyncio.sleep(2)  # 模擬 I/O 工作
        print(f"完成處理 {param}")

async def main(params):
    sem = asyncio.Semaphore(3)  # 同時最多允許3個併發
    tasks = [asyncio.create_task(worker(sem, p)) for p in params]
    await asyncio.gather(*tasks)

params = list(range(10))
asyncio.run(main(params))

這樣即使建立了 10 個任務,也會同時最多執行 3 個,避免過度佔用資源。


錯誤處理

非同步函式裡也可以用 try/except 捕捉例外,錯誤會往上拋,讓你能集中處理。

async def might_fail():
    await asyncio.sleep(1)
    raise ValueError("出錯了!")

async def main():
    try:
        await might_fail()
    except ValueError as e:
        print("捕捉到錯誤:", e)

asyncio.run(main())

非同步 vs 同步的比較

面向 同步 非同步
執行模式 逐步等待完成 可同時等待多個任務
資源使用 可能阻塞,浪費等待時間 更有效率,充分利用等待時間
程式設計 直觀,但對I/O不友好 需設計非同步流程,較複雜

小結

  • 使用 async defawait 寫非同步函式
  • 利用 asyncio.run() 啟動事件循環
  • asyncio.gather() 可以同時跑多個協程
  • asyncio.Semaphore 控制同時執行數量,避免過度佔用資源
  • try/except 做非同步錯誤處理
  • 非同步適合 I/O 密集、等待較長的場景

如果你想了解更進階的非同步網路程式設計(如 aiohttp)、資料庫非同步操作,或事件循環底層運作,歡迎留言討論!

Promise.then() vs async/await:該怎麼選擇?

在撰寫 JavaScript 的非同步程式時,我們通常有兩種主流方式來處理 Promise 的結果:

  • 使用 .then() 搭配 .catch()
  • 使用 async/await 搭配 try/catch

那麼問題來了:
當你要拿一個 Promise 的結果做後續處理時,該用哪一種方式?

這篇文章會帶你比較兩者的差異、優缺點,並給出實務上的建議。

🔁 基本寫法比較

使用 .then()

fetchData()
  .then(data => {
    console.log("資料取得成功:", data);
  })
  .catch(err => {
    console.error("發生錯誤:", err);
  });

使用 await

async function main() {
  try {
    const data = await fetchData();
    console.log("資料取得成功:", data);
  } catch (err) {
    console.error("發生錯誤:", err);
  }
}
main();

✅ 各自的優缺點

項目 .then() async/await
可讀性 多層 .then() 可能會變難讀 結構接近同步邏輯,可讀性高
錯誤處理 使用 .catch() 可使用 try/catch 處理錯誤
控制流程 條件判斷或迴圈處理不直觀 iffor 等控制流可自然搭配使用
使用場景 非 async 環境(如模組頂層)適用 必須在 async 函式中使用
串接多個任務 .then().then().then() 較直覺 多個 await 也清楚,但需搭配邏輯

🧠 多段傳遞差異

.then() 支援連鎖傳值

Promise.resolve(2)
  .then(x => x * 3)        // 傳遞 6
  .then(y => y + 1)        // 傳遞 7
  .then(z => console.log(z)); // 印出 7

await 要自己手動接收變數

async function run() {
  const x = await Promise.resolve(2);
  const y = x * 3;
  const z = y + 1;
  console.log(z); // 印出 7
}

⚠️ 注意:.catch() 後還能繼續 .then()

你可能會以為錯誤後整個鏈就中止了,其實不是:

doSomething()
  .catch(err => {
    console.warn("錯誤被攔截:", err);
    return "預設值";
  })
  .then(result => {
    console.log("後續繼續執行:", result); // 收到預設值
  });

.catch() 沒有拋出新的錯誤,Promise 鏈會繼續執行後面的 .then()

🎯 什麼情況用哪一個?

建議使用 async/await:

  • 寫長流程邏輯時(可讀性更高)
  • 有多個非同步步驟需依序處理
  • 錯誤處理邏輯較複雜

建議使用 .then():

  • 在模組頂層(不方便加 async
  • 想快速串接簡單處理流程
  • 喜歡函式式風格或鏈式操作

✅ 結論

無論使用 .then() 還是 async/await,它們本質上都在操作 Promise。

  • .then() 更像函數式管線
  • await 更像同步的控制流
  • .catch() 可以中斷 .then() 鏈,也可以處理錯誤後繼續執行
  • .finally() 可以寫多個,做收尾工作

建議平時盡量用 async/await 搭配 try/catch
除非你的環境或需求更適合 .then() 鏈式處理。

如果你想要更深入的示範(例如多個非同步任務併發、錯誤復原機制、top-level await 實務寫法),也歡迎留言或關注後續文章。

2025年3月8日 星期六

Linux 桌面環境打字時隱藏滑鼠游標

我用的是 Linux Mint 一直找不到控制台裡的打字時隱藏滑鼠游標功能

經過一番搜尋找到兩個套件:unclutterxbanish

unclutter 的用處是可以指定多少時間之後隱藏滑鼠游標

xbanish 的用處是按鍵盤後隱藏滑鼠游標,決定使用 xbanish 試試看

安裝方法很簡單:sudo apt install xbanish

裝好之後在終端機裡執行 xbanash 就能生效

若要開機後自動啟動,可以在 ~/.profile 或是 ~/.bashrc 的最後加一行

xbanish &

就可以了