December 17, 2018

LEMP HTTP 502 PHP

最近幫朋友架設網頁伺服器,架構是用經典的 LEMP (Linux + nginx + MySQL + PHP) ,遇到了在他的電腦上可以用,在我設定的伺服器上卻跑不了的問題,打開它寫的 php 網頁會出現 502 Bad Gateway 。

遇到這樣的狀況,朋友毫不猶豫的說是伺服器的問題,『反正在我的電腦上可以跑』,類似的話,身為設定伺服器的人聽到這樣的話當然是非常的不爽,但沒辦法,只好找出問題出來才能證明清白。

遇到的狀況是:打開所有的 php 程式都可以正常執行,只有某一個會出現 502 ,於是開始看那個出問題的程式。不過會出現 502 也是蠻意外的,因為如果是程式有 bug ,那大概會跳出 exception 之類的東西,或是 warning ,但這個卻直接 502。

接著我看著他的程式碼,主程式有 500 行,不過大部份都是可以用迴圈代替的東西,主程式有 include 其他 php ,每個 php 也有 200-300 行,幾乎也都是可以用迴圈代替的東西。

main.php
├── include sub1.php
├── include sub2.php
├── include sub3.php
├── include sub4.php
└── include sub5.php

先試試把 include 都註釋掉,發先可以運行,所以我猜問題大概不在主程式,接著放第一個 include 近來,還是不會出現 502 ,放第二個 include 近來之後,502 出現了!!

於是我進入第二個 include 的檔案看看,這次我先把它全部註釋掉,然後一部分一部分取消註釋,直到找到會出現 502 的那一行。

終於找到那一行之後,發現那一行跟前面的幾行並沒有什麼大不同,於是我試著註釋上一行,不會出現 502 了!

剛剛所有註釋掉的東西大部分都是 `setcookie()` ,所以實際上如果沒有出現 502 的話,他的程式大概會有幾百個 setcookie ,於是我試試是不是因為 setcookie 太多所導致的問題。

<?php

for ($i = 0; $i < 100; ++$i)
{
    setcookie('a' . $i, $i);
}

跑完這段之後沒有問題,再把 100 改成 1000 之後,同樣也出現了 502 ,所以原因就是他用了太多的 setcookie 了,header 太大 nginx 就當作 502 來處理了。下面類似的代碼也會導致 502 。

<?php

for ($i = 0; $i < 1000; ++$i)
{
    header('h' . $i . ': ' . $i);
}

後來得知他使用那麼多 setcookie 的原因,他想把 cookie 當作傳送資料的途徑, 因為那不是 cookie 的用途,所以我拒絕去修改設定。

總知, Header size 不能超過 nginx 設定,不然會被 502 。

故事小細節:這是學生專題,他們組在寫網頁,因為不是我的組的,所以也沒有介入太多。結論2:幫別人忙還是收錢好,不然沒錢賺還要莫名其妙的被嗆。