有支有陣子沒怎麼用到的程式忽然無法完整跑完,一開始看到 Apache 上的錯誤訊息寫這樣:
[Tue Jun 02 12:35:38.163897 2020] [proxy_fcgi:error] [pid 000000:tid 999912345678900] (70007)The timeout specified has expired: [client 127.0.0.1:12345] AH01075: Error dispatching request to : (polling)
大部分的文章說是需要把逾時的時間拉大一點,讓程式有機會可以慢慢跑完,譬如去修改 Apache 的 config 裡的以下值:
- Timeout
- ProxyTimeout
- FcgidIdleTimeout
- FcgidProcessLifeTime
- FcgidConnectTimeout
- FcgidIOTimeout
(可能會在 httpd.conf 或 fcgid.conf 裡,視之前設定的位置而定)
但是因為這是一個小~小~的程式,我覺得應該不至於需要那麼多的資源與時間,所以轉而檢查了一下程式。後來發現是卡在 Google reCAPTCHA 要向 Google 驗證時,會跑個大約 60 秒後才吐 Exception。(視 Web Server 與 PHP 可接受的逾時時間而定)
看了一下同事的寫法和我的寫法,我在兩年前是這樣寫的:
<?php
$gRecaptchaResponse = $_POST["g-recaptcha-response"]; // 從前端送來的 Google reCAPTCHA 表單驗證值
$reCaptchaUrl = "https://www.google.com/recaptcha/api/siteverify"; // Google Verify URL
$secret = "(Google reCaptcha Key)"; // Your Key
$curl = curl_init();
// 我原本的寫法
curl_setopt($curl, CURLOPT_URL, $reCaptchaUrl."?secret=".$secret."&response=".$gRecaptchaResponse); // Using GET method
// --------------------
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
$result = curl_exec($curl);
?>
而我同事的寫法是這樣,我們的差別在於我用了 GET、他用了 POST 向 Google 進行驗證:
<?php
$gRecaptchaResponse = $_POST["g-recaptcha-response"]; // Google
$reCaptchaUrl = "https://www.google.com/recaptcha/api/siteverify"; // Google Verify URL
$secret = "(Google reCaptcha Key)"; // Your Key
$curl = curl_init();
// 從這裡開始不一樣
curl_setopt($curl, CURLOPT_URL, $reCaptchaUrl);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT , 5); //to connection Google Recaptcha server in 5 seconds.
curl_setopt($curl, CURLOPT_TIMEOUT, 10); // to get response from Google Recaptcha server in 10 seconds.
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query(array("secret"=>$secret, "response"=>$gRecaptchaResponse)));
// --------------------
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
$result = curl_exec($curl);
?>
上網查一下,在 stackoverflow 看到也有人一年多前在問 "Recaptcha v2 verification",回答者說對 server 要驗證那段一定要用 POST。
在 Google reCAPTCHA 的 developer guides 上面沒有看到特別說什麼時候起要改成用 POST,不過 "Verifying the user's response" 這段是直接指定一定要用 POST 進行驗證。
修改後就好了~感謝世上有 Google 大神與強者我同事。
(2020/12/22 update!) 發現在 IE 裡,前端的 JavaScript 無法正確初始化 Google reCaptcha,會出現錯誤訊息:「物件沒有支援這個屬性或方法 'querySelector'」(Object doesn't support property or method 'querySelector')。
因為這個錯誤訊息是來自於 Google reCaptcha 的核心 api.js 被中斷了,所以要初始化 Google reCaptcha 的前端語法根本執行不了:
grecaptcha.ready(function() {
grecaptcha.execute('replace_to_your_recaptcha_token', {action: 'form_submit_button'}).then(function(token) {
$("#g-recaptcha-response").val(token);
});
});
按 F12 打開 IE 的開發者工具 (developer tool),發現 IE 的模式預設被設定為 IE 5,這個預設模式是來自於 DOCTYPE 宣告,不過把它改成最簡化的 DOCTYPE,預設也還是會是 IE7 模式:
<!DOCTYPE html>
最後加入一行 META,強制以 IE edge 模式執行,結束這回合:
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
留言列表