2020年11月16日 星期一

HTML 上傳按鈕美化

方法:
  1. 隱藏原本的上傳按鈕,另外做一個按鈕。
  2. 點擊另外做的按鈕時,觸發原本上傳按鈕的點擊事件。
  3. 選擇完上傳檔案後,另外顯示選擇檔案的檔名。


[做法1]

用<label></label>標籤,讓另外做的按鈕能觸發原本上傳按鈕的動作。
<input id="xyzFileUp" class="xyzFileUp" type="file" name="ff" style="display:none">
<label for="xyzFileUp" class="xyzFileUpSel">選擇檔案(另外做的按鈕)</label>
<div class="xyzFileUpFileName">
未選擇檔案
</div>

<script>
//顯示選擇的上傳檔案檔名
$(".xyzFileUp").on("change", function () {
    var filePath = $(this).val();
    var arr = filePath.split('\\');
    var fileName = arr[arr.length - 1];
    $(".xyzFileUpFileName").html(fileName);
});
</script>


[做法2]
用JS,讓另外做的按鈕能觸發原本上傳按鈕的動作。
<input id="xyzFileUp" class="xyzFileUp" type="file" name="ff" style="display:none">
<div class="xyzFileUpSel">選擇檔案(另外做的按鈕)</div>
<div class="xyzFileUpFileName">
未選擇檔案
</div>

<script>
//觸發原本上傳按鈕
$('.xyzFileUpSel').click(function () {
    document.getElementById("xyzFileUp").click();
    //$("#xyzFileUp").click();
});
//顯示選擇的上傳檔案檔名
$(".xyzFileUp").on("change", function () {
    var filePath = $(this).val();
    var arr = filePath.split('\\');
    var fileName = arr[arr.length - 1];
    $(".xyzFileUpFileName").html(fileName);
});
</script>



參考:
css input[type=file] 样式美化,input上传按钮美化
自訂 Input File 檔案上傳按鈕 CSS 最佳解法﹍實作範例@WFU BLOG
html - Styling an input type="file" button - Stack Overflow
在網頁應用程式中使用本地檔案 - Web APIs | MDN::使用click() 方法隱藏檔案輸入元素
HTMLElement.click() - Web APIs | MDN


Nginx 出現 upstream sent too big header while reading response header from upstream 錯誤,回應 502 Bad Gateway

[環境]
Server A(192.168.56.10) 使用 Nginx 設定 Load Balance 負載平衡。
proxy_pass 給 Server B(192.168.56.11)、Server C(192.168.56.12),真正處理的 Web Server。

Server A(192.168.56.10) 設定
upstream myweb {
    server 192.168.56.11 weight=3;//Server B
    server 192.168.56.12 weight=3;//Server C
}
server {
    listen 80;
    server_name example.com;
    location / {
        proxy_pass http://myweb;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto http;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
    access_log /var/log/nginx/access.log main;
    error_log /var/log/nginx/error.log warn;
}
當 Server B、Server C 輸出的 header 過大,超出 Server A 的限制,Server A 接收到 Server B、Server C 時會:
  1. 直接回應 502 Bad Gateway 給使用者端
  2. 在 Server A 的 access.log 可看到 502 相關的紀錄:
    ...."GET / HTTP/1.1" 502 568 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleW....
  3. 在 Server A 的 error.log 可看到[error]層級的錯誤:
    [error] 5131#5131: *10 upstream sent too big header while reading response header from upstream....
但對 Server B、Server C 而言,工作都已正常完成,所以 log 都是正常的。
故若不經過 Server A,直接瀏覽 Server B、Server C 會是正常的。


[解決方法]
如果過大的 header 是預期中、必要的,可在  Server A 加大 proxy buffer 限制
location / {
    .....
    proxy_buffer_size 64k;
    proxy_buffers 4 32k; //proxy_buffers number size
    proxy_busy_buffers_size 64k;
    .....
}


參考:
Module ngx_http_proxy_module
修復Nginx 502錯誤:upstream sent too big header while reading response header from upstream - IT閱讀



Nginx 從 HTTP/1.1 改用 HTTP/2 (優化網頁速度)

打開 Chrome 開發者工具,如果看到網頁載入的資源(CSS、圖片、JS...),很多時間花在Queueing,
那將網站從 HTTP/1.1 升級到 HTTP/2,可大大改善網站速度。
因為 HTTP/1.0、HTTP/1.1,同一個網域只能有6個 TCP 連線(以目前的chrome為例),
所以當網頁的資源連結很多,會發生排隊阻塞的情況,載入時間累計就慢了。

以前在 HTTP/1.0、HTTP/1.1 的連線數限制下,可用 Domain sharding 的方式解決,
Domain sharding:將資源的請求,分配到不同的網域,以突破連線數的限制。

現在 HTTP/2 採用多路復用,讓資源的請求合併在同一個 TCP 連線內,可以解決排隊阻塞的情況。

HTTP/2 跟 HTTP/1.1 有高度相容性,但 HTTP/2 只能在 https 的環境執行,
所以若網站原本就用 https,或沒特殊情況須用 http,
那只須 Nginx 設定使用 https 並開啟 http2 即可。

[Nginx 開啟 HTTP/2]
先確認安裝的 nginx 有支援 HTTP/2

  1. nginx 版本 1.9.5 以上
    (HTTP/2 Supported in Open Source NGINX 1.9.5 | NGINX)
  2. nginx 使用的 OpenSSL 版本 1.0.2 以上
    目前HTTP/2使用ALPN(Application-Layer Protocol Negotiation、一個傳輸層安全協定(TLS) 的擴充),而OpenSSL在1.0.2後開始支援ALPN
    (應用層協定協商 - 維基百科,自由的百科全書)
  3. nginx 編譯參數有開啟ngx_http_v2_module模組,--with-http_v2_module
使用「nginx -V」查看相關資訊
# nginx -V
nginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx
..... --with-http_v2_module .....

確定都符合後,只須在 nginx 網站設定檔上,加上「http2」即可。
例如,原本

server {
    ...
    listen 443 ssl;
    ...
}
加上「http2」,改成
server {
    ...
    listen 443 ssl http2;
    ...
}
# systemctl reload nginx.service

[測試:HTTP/1.1、HTTP/2]
圖一:HTTP/1.1,瀏覽有2000個圖片的頁面,花7.63秒。

圖二:HTTP/2,瀏覽有2000個圖片的頁面,花4.73秒。


[其他:chrome開發者工具request時間區段說明]

  • Queueing. The browser queues requests when:
    There are higher priority requests.
    There are already six TCP connections open for this origin, which is the limit. Applies to HTTP/1.0 and HTTP/1.1 only.
    The browser is briefly allocating space in the disk cache
  • Stalled. The request could be stalled for any of the reasons described in Queueing.
  • DNS Lookup. The browser is resolving the request's IP address.
  • Initial connection. The browser is establishing a connection, including TCP handshakes/retries and negotiating an SSL.
  • Proxy negotiation. The browser is negotiating the request with a proxy server.
  • Request sent. The request is being sent.
  • ServiceWorker Preparation. The browser is starting up the service worker.
  • Request to ServiceWorker. The request is being sent to the service worker.
  • Waiting (TTFB). The browser is waiting for the first byte of a response. TTFB stands for Time To First Byte. This timing includes 1 round trip of latency and the time the server took to prepare the response.
  • Content Download. The browser is receiving the response.
  • Receiving Push. The browser is receiving data for this response via HTTP/2 Server Push.
  • Reading Push. The browser is reading the local data previously received.


參考:

2020年10月1日 星期四

設定特定連線才使用VPN

環境:win10,已新增一個VPN連線 (IP:a.b.c.d,連線名稱:SV)

目的:限制只有跟 IP w.x.y.z 的連線,才使用 VPN


步驟:

  1. 預設啟用VPN後,所有連線,都會經過VPN,先取消此設定。
    到「控制台\所有控制台項目\網路連線」,於 VPN 連線上
    按右鍵->「內容」->「網路功能」->「網際網路通訊協定第4版(TCP/IPv4)」->「內容」->「進階」->不要勾選「使用遠端網路的預設閘道」





  2. 啟用 VPN。(經過步驟1的設定後,此時啟用 VPN,連線也不會經過 VPN。)
    然後使用「route print」指令,找出 VPN 連線的介面ID。
    如下,可知名稱 SV 的 VPN,介面ID 為 57
    C:\WINDOWS\system32>route print
    ===========================================================================
    介面清單
     12...0a 00 27 00 00 0c ......VirtualBox Host-Only Ethernet Adapter #10
     16...0a 00 27 00 00 10 ......VirtualBox Host-Only Ethernet Adapter #9
     57...........................SV
      1...........................Software Loopback Interface 1
    ===========================================================================

  3. 將要經過 VPN 的連線,設進路由。
    假設跟 IP w.x.y.z 的連線,才要經過VPN,可如下設定,加入路由表
    route add -p w.x.y.z mask 255.255.255.255 0.0.0.0 if 57
    參數 -p:預設電腦重啟、VPN關閉重啟,設定會取消。加上 -p 參數可保留設定。
    閘道 0.0.0.0:0.0.0.0 使用預設路由,也可以指明設定IP

    再使用「route print」指令檢查使用中的路由表,應該可以發現多了以上的設定
    C:\WINDOWS\system32>route print
    ===========================================================================
    介面清單
     12...0a 00 27 00 00 0c ......VirtualBox Host-Only Ethernet Adapter #10
     16...0a 00 27 00 00 10 ......VirtualBox Host-Only Ethernet Adapter #9
     57...........................SV
      1...........................Software Loopback Interface 1
    ===========================================================================
    
    IPv4 路由表
    ===========================================================================
    使用中的路由:
    網路目的地                 網路遮罩         閘道          介面       計量
              0.0.0.0          0.0.0.0      192.168.0.1    192.168.0.8    281
             10.0.0.0        255.0.0.0     10.10.10.101      10.10.10.50     26
          10.10.10.50  255.255.255.255            在連結上       10.10.10.50    281
              w.x.y.z  255.255.255.255            在連結上       10.10.10.50     26
              a.b.c.d  255.255.255.255      192.168.0.1    192.168.0.8     26

  4. 若要刪除上面的 route 設定
    route delete w.x.y.z mask 255.255.255.255 0.0.0.0
    或
    route delete w.x.y.z mask 255.255.255.255


參考:
Shunze 學園 - 《分享》增加VPN連線後的遠端網段路由
Windows 雙網路搭配雙網卡 @ Welkin小窩 :: 痞客邦 ::
networking - How can I make the Windows VPN route selective traffic (by destination network)? - Super User


2020年9月6日 星期日

jQuery Datepicker 增加清除按鈕

原本 jQuery Datepicker 的操作按鈕面板(showButtonPanel: true),只有「Today」、「Done」,兩個按鈕。
沒有清空日期的按鈕,只能於input上,將選擇的日期手動清除。
$(".test").datepicker({
    dateFormat: "yy-mm-dd",
    showOn: "both",
    buttonImageOnly: true,
    showButtonPanel: true,
    buttonImage: "img/calendar.png"
});


此處增加「Clear」按鈕,用來清空選擇的日期。

方法一:
參考 https://stackoverflow.com/a/15799622
將「Done」按鈕,修改成為清空的效果。缺點是「Done」按鈕不見了。

$(".test").datepicker({
    dateFormat: "yy-mm-dd",
    showOn: "both",
    buttonImageOnly: true,
    showButtonPanel: true,
    closeText: 'Clear',
    onClose: function (dateText, inst) {
        if ($(window.event.srcElement).hasClass('ui-datepicker-close')) {
            document.getElementById(this.id).value = '';
        }
    },
    buttonImage: "img/calendar.png"
});


方法二:
參考 https://stackoverflow.com/a/6941440https://stackoverflow.com/a/28045758
另外新增一個「clear」按鈕。

//另外新增一個clear按鈕
function datepickerAddClearBtn() {
        var old_fn = $.datepicker._updateDatepicker;
        $.datepicker._updateDatepicker = function (inst) {
        old_fn.call(this, inst);
        var buttonPane = $(this).datepicker("widget").find(".ui-datepicker-buttonpane");

        $("<button type='button' class='ui-datepicker-clean ui-state-default ui-priority-primary ui-corner-all'>Clear</button>").appendTo(buttonPane).click(function (ev) {
            $.datepicker._clearDate(inst.input);//清除選擇的日期
            $.datepicker._hideDatepicker();//關閉Datepicker
        });
    };
}
datepickerAddClearBtn();

$(".test").datepicker({
    dateFormat: "yy-mm-dd",
    showOn: "both",
    buttonImageOnly: true,
    showButtonPanel: true,
    buttonImage: "img/calendar.png"
});




其他:
jQuery-Timepicker-Addon 附加套件上亦適用