顯示具有 網站設計 標籤的文章。 顯示所有文章
顯示具有 網站設計 標籤的文章。 顯示所有文章

CORS Error:the resource is in more-private address space 'private'

 今天在學習React.js時,利用fetch api來取得JSON的資料時,出現了CORS的錯誤:
The request client is not a secure context and the resource is in more-private address space `private`.



但是我在Server端已經設定好CORS,應該不會出現這個訊息才是。

後來在網路上找到了問題,原來是chrome在版本94之後,它不允許不安全的公網(訪問者)存取不安全的私網资源。

解決的其中一個方式是將兩邊的網路都設置為https,但是我只是學習而已,好像沒有必要設定SSL

另一個方式是進入chrome的設置頁:chrome://flags ,找到Block insecure private network requests,把值設定為disable





Cannot use import statement outside a module

 今天在練習vue的時候,在瀏覽器中遇到了下列的錯誤:
Uncaught SyntaxError: Cannot use import statement outside a module 

這個原因是在HTM網頁中,透過script標籤加載Javascript腳本,但是瀏覽器默許的腳本語言是Javascript,因此我一般都是省略了type="application/javascript",而module的加載方式是ES6的實現,所以需要在script標籤中加入type="module"

例如:
<script type="module">
    import ButtonCounter from './element.js'
</script>

Oracle WebLogic 12c建置靜態網頁

 最近正好在自己的電腦上嘗試安裝好Oracle WebLogic 12c,也試著安裝了Forms and Reports。

WebLogic既然可以部署和管理Web,應該也可以建置靜網頁。於是在網路上找了一下文件,依步驟設定後已成功,記錄一下。

1、建立新資料夾,如Static_Website,並且新增test.html

2、在資料夾Static_Website底下再新建一個資料夾,名稱為WEB-INF,並且新增一個web.xml,內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>Static HTML</display-name>
  <welcome-file-list>
    <welcome-file>test.html</welcome-file>
 </welcome-file-list>
</web-app>

3、在WEB-INF資料夾底下再新建一個weblogic.xml,內容如下,其中<context-root>是指定路徑:

<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app xmlns="http://www.bea.com/ns/weblogic/weblogic-web-app">
  <context-root>/test</context-root>
</weblogic-web-app>

4、到Weblogic Server主控台中開始部署





接著就都依預設值來進行,直到完成

5、完成部署後,需要將其啟動


6、打開瀏覽器,輸入URL,可以正常顯示test.html的內容





利用nginx + reverse ssh tunnel 架設臨時對外網頁服務

 我有一台內部區網的測試用網頁伺服器,因為有需要由外網來測試網頁,所以我是用ngrok來讓外網可以連到內網的測試網頁。

最近在網路上看到reverse ssh tunnel的技術文件,加上我在Cloud上有一台nginx的反向代理伺服器,所以就順著文件來模擬ngrok。

公開的網址是:test1.twtnn.com

內部的網址是:http://192.168.10.10:2222

在ngrok的設定檔新增一個設定如下:

server {
  server_name test1.twtnn.com;
  location / {
      proxy_pass http://localhost:17777/;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

其中proxy_pass就是當連線test1.twtnn.com時會轉送到http://localhost:17777

如果nginx與你的local server間使用的 https則可以加上proxy_set_header X-Forwarded-Proto https; 

接著在內網的伺服器設定reverse ssh tunnel,因為Cloud是用private key登入的,所以要加上-i

$ ssh -R 17777:localhost:2222 -i privte.key account@test1.twtnn.com   

-R可以讓test1.twtnn.com上面的port:17777反向連入內部本機的port:2222

接著在瀏覽器開啟網址:http://test1.twtnn.com,就可以瀏覽內部的網頁了。



利用Edge的webauthn虛擬驗證程式來測試webauthn網頁

 最近在學習無密碼登入,所以依樣寫了一個希望能用指紋來登入的測試網頁。

因為每次在PC端修改完要測試時,就需要把網頁上傳到伺服器上並且用手機開啟來測試。

如今無意間發現微軟的一篇文章有提到可以用Edge來模擬webauthn,網址如下:

https://docs.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/webauthn/

我的部份程式如下,希望使用指紋的功能


在Edge把webauth的功能頁打開,設定一個新的驗證器



傳輸有四個選項:

usb:removable USB.

nfc:Near Field Communication (NFC).

ble:Bluetooth Smart (Bluetooth Low Energy / BLE).

internal:a client device-specific transport, i.e., it is a platform authenticator. 

新增完成後,一開始是沒有任何認證的,如下圖


接著把我的webauthn測試頁網載入,就成功產生了一個認證,這樣就不必再用手機來測試了。


還可以把認證移除或匯出,以後續驗證使用。



nginx+uwsgi+flask:CORS跨網域錯誤解決

 我有一個以nginx+uwsgi+flask架設的Web API服務,但是在網頁呼叫該API時,瀏覽器出現了CORS跨網域錯誤。

這是瀏覽器為了安全性而設置的規則,我找到兩個方案:一個以flask來設置;另一個以nginx來設定。


flask方案(因為我用nginx架設服務,所以我不確定該方式是否有效的):

1、安裝 flask_cors 套件:pip install flask_cors  

2、程式如下:  

    from flask import Flask  

    from flask_cors import CORS  

    app = Flask(__name__)  

    CORS(app)    

    @app.route("/")  

    def helloWorld():  

        return "Hello!"  


nginx方案(我用此方案):

在設定檔nginx.conf的每個區段加入下列語法:

    add_header Access-Control-Allow-Origin *;  

    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';  

    add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';  

程式範例如下:  

location /ft-prtg {

        add_header Access-Control-Allow-Origin *;

        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';

        add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

        default_type "text/html";

        alias /test/html/test_FT.html;

    } 


重啟nginx之後,在瀏覽器的開發工具檢示其結果如下,已加在Header上了。




Flask + uWSGI + Nginx架設記錄

我有一支用Python開發的http api程式,是以http.server的module啟動service,但是這僅適合測試環境使用。

後來我把Python改以Flask開發,但是Flask預帶的Web Service也不被建議用在正式環境上。

所以最後我用Flask + uWSGI + Nginx來完成正式環境的架設,記錄一下以免之後忘記了。

安裝Flask、uWSGI、Nginx程式,我的作業系統是ubuntu

# apt install nginx
# pip3 install Flask
# pip3 install uwsgi

我的測試Flash程式,檔名server.py,內容如下:

from flask import Flask
app = Flask(__name__)
@app.route("/")
def test():
    return "相思樹下數相思,怨君不知相思苦"
if __name__ == '__main__':
	app.run()

啟動flask服務,利用curl http://127.0.0.1:5000來看看是否有傳回「相思樹下數相思,怨君不知相思苦」

# python server.py


uWGI可以使用三種協定設定,而nginx則必需配合uWGI的協定來配置

1、socket協定

------------------

uWSGI設定,新增一個配置檔,如uwsgi_test.ini

[uwsgi]
module			= server:app
chdir			= /test_flask
master			= true
processes		= 3
socket			= /var/run/test_uwsgi.sock
die-on-term		= true
chmod-socket	= 666
logto			= /var/log/uwsgi_test.log

moule是設定flask的檔案(不用加.py)及入口程序名,以測試檔server_flask.py而言是指app

chdir是flask程式的路徑

processes是指定uWGI要啟用多少個process

socket是設定scoket的檔案位置,nginx與uWGI依靠這個檔案相互搭起

chmod設定權限,我有試過設定660,結果造成nginx無法讀取socket檔案

logto是設定log的目錄

nginx設定,在/etc/nginx/sites-available內新增配置檔,如webtest.conf

server {
    listen      80;
    charset     utf-8;

    location / {
        try_files $uri @app;
    }
    location @app {
        include     uwsgi_params;
        uwsgi_pass  unix:/var/run/uwsgi_server.sock;
    }
    location /test {
        default_type "text/html";
        alias /html/test01.html;
    }
	location /js {
	    alias /html/js;
	}
}   


2、http協定

-------------------------

uWSGI 配置:

[uwsgi]
wsgi-file = /test_flask/server.py
callable = app
http= :8000
processes = 3
threads = 2
master = true
chmod-socket = 660
vacuum = true
die-on-term = true


wsgi-file是flask的完整檔名



Nginx 配置:

server{
    listen  80;
    location /{
        proxy_pass  http://127.0.0.1:8000;
    }
}


3、uwsgi協定

--------------

uWSGI 配置

[uwsgi]
wsgi-file = server.py
callable = app
socket = :8000
processes = 4
threads = 2
master = true
chmod-socket = 660
vacuum = true
die-on-term = true


Nginx 配置

server{
    listen  80;
    location /{
        include uwsgi_params;
        uwsgi_pass 127.0.0.1:8000;
    }
}


啟動uWSGI、nginx:

# uwsgi test.py
# nginx


利用curl http://127.0.0.1來看看是否成功傳回「相思樹下數相思,怨君不知相思苦」

利用Chrome DevTools自動輸入測試資料

 我有一個網頁程式是新增資料用的,當測試時都需要自己key測試資料,文字欄位一多,測試次數又多,是很累人的。

當然有許多的方法及軟體都可以做到這樣的事情,而且功能更加強大。不過我試著用Chrome Developer Tools來嘗試。因為有試出來,故記錄下來。

網頁如下圖,有一些文字欄位要輸入,而且都是必填的欄位



首先找出元素的Selector路徑,按F12開啟Chrome DevTools,選擇網頁上的元素並按下滑鼠右鍵選擇「檢查」

接著Chrome就會在DevTools的Elements頁面反白出元素的html原始碼,在反白的元素原始碼按下滑鼠右鍵,選擇「Copy」-> 「Copy JS path」,如下圖


例如找出來的Selector Path如下:document.querySelector("#itemID")

在DevTools的Console頁面輸入document.querySelector("#itemID").value='1001',這樣網頁上的文字欄位就自動填上測試值了,如下圖:



只要重覆找出需要輸入的元素後,把它全部集中在一起,之後利用複製貼上就可以一次讓網頁上的欄位都自動填上測試資料。

Python TOTP、HOTP測試

 一開始接觸OTP是因為註冊一個雲端平台的測試帳號後,開啟兩階段認證的選項,進而產生興趣。


我們的VPN也有啟用兩階段的認證,當然它是商用版。網路上有一套FreeOTP的開源程式,有支援Android與IOS


OTP(one-time password)稱為一次性密碼,又稱動態密碼或單次有效密碼,在一段有效期只能使用一次的密碼。


原本以為需要架設網路服務來產生密碼與認證,但是看了一下FreeOTP官網卻看不到有任何Server端的安裝文件。


原來OTP是不需要網路服務的,OTP用一組金鑰並搭配變數,例如時間,利用演算法讓伺服器端及用戶端可以產生一

樣的密碼,且這組密碼會隨時間變動失效。


目前常見的OTP密碼傳送方式有簡訊與手機APP,簡訊是由服務端(伺服器)產生密碼後,寄送到使用者的手機上,


而APP則是在用戶端(手機)自行產生密碼,再將密碼鍵入伺服器端來認證,這種方式完全不需要網路服務的。


我測試了兩種不同的技術:HOTP與TOTP,程式語言是python,不過網頁也有相關的模組,原理都是一樣的。


Event Base - OATH HOTP:

HOTP 是HMAC-based One-Time Password的簡寫,雜湊函數加密的一次性密碼。

變動因子Counter 值(OTP 的產生次數)每個密碼僅在一次驗證中有效。

公式:OTPc = HOTP(Key,Counter) = Truncate(HMAC-SHA1(Key,Counter))


Time Base - OATH TOTP:

TOTP 是Time-based One-Time Password的簡寫,表示基於時間戳算法的一次性密碼。

由於量以時間為變數因子,所以用戶端和伺服器時間必須保持一樣,否則會產生不一致的密碼。

公式:OTPt = HOTP(Key,Time) = Truncate(HMAC− SHA1(Key,Time))


以下是我實測的過程與自己的一點小小心得,記錄下來。


首先安裝模組,我用的是pyotp

pip install pyotp


金鑰是Base32格式,所以有下列兩種方式可以產生。

1、pyotp.random_base32() => 直接產生一組隨機的金鑰

2、(base64.b32encode(bytearray("abcd", 'ascii')).decode('utf-8') => 指定字串轉換成Base32


python測試HOTP,金鑰是abcdefg:

>>> import pyotp

>>> hotp = pyotp.HOTP('abcdefg') 

>>> hotp.at(2) #產生密碼

'922982'

>>> hotp.verify('922982',2) #驗證密碼

True

>>> hotp.verify('922982',1)

False

>>> hotp.at(3)

'480228'

>>> hotp.verify('922982',2)

True

>>> hotp.verify('480228',3)

True



python測試TOTP,金鑰是abcdefg,目前預設有效期是30秒:

>>> import pyotp

>>> import time

>>> totp = pyotp.TOTP('abcdefg')

>>> totp.now() #利用時間來產生密碼

'153947'

>>> totp.verify('153947') #驗證密碼 

True

>>> time.sleep(30) #等待30秒

>>> totp.verify('153947') #驗證密碼

False

>>> totp.now() #重新產生密碼

'288940'

>>> totp.verify('288940') 

True



測試APP TOTP,金鑰是abcdefg,目前預設有效期是30秒,使用FreeOTP App或Google Authenticator:

pyotp.totp.TOTP('abcdefg').provisioning_uri(name='Test@test.com', issuer_name='TEST App')

>>> 'otpauth://totp/Secure%20App:alice%40google.com?secret=JBSWY3DPEHPK3PXP&issuer=Secure%20App'

將上一步驟的otpauth的字串複製下來,到免費的產生QRCode網站產出QRCode



在手機上開啟FreeOTP App或Google Authenticator,掃描QRCode來註冊,APP每隔一段時間就會產生一組新密碼

驗證密碼的程式下:

>>> import pyotp

>>> atotp = pyotp.TOTP('abcdefg') #金鑰需要一樣的。

>>> atotp.verify('598189') #將手機APP上的密碼鍵入驗證

True

>>> atotp.now() #也可以自行產生一組密碼



所以建立兩階段的程式設計流程應該是這樣:

1、建立一個記錄帳號密碼及key的資料庫

2、依據key來產生一組otpauth註冊碼

3、FreeOPT或Google Authenticator登錄註冊碼

4、使用者開啟程式並輸入帳號及密碼,先檢查帳號密碼無誤,此為第一階認證

5、再到資料庫抓出key值,以及FreeOPT或Google Authenticator產生的密碼放入檢查程式來確認

6、如檢查結果為true,則通過第二階認證,程式就可以回傳認證成功

7、只要把帳號的key值刪掉或改掉,則第二階認證就會失敗,所以控制權在內部人員手上,使用者不必做任何動作。


如果要以簡訊或Mail來傳送TOTP的密碼,則更改上述第5步驟即可

Node.js Response 中文亂碼

 今天在測試node.js時,response出來的中文變成亂碼,在網路上找了一些文件及自己最後解決方式,記錄一下。


我的情形是這樣的,我在Windows上的docker有跑一個node.js,中文顯示是正常的;我在Cloud上跑的node.js,中文顯示是亂碼。但是程式碼內容是一樣的。

Cloud上安裝是Debian GNU/Linux 9 (stretch)


網路上有提到文件需要是utf-8的格式,所以我在Cloud上檢查我的app.js檔:

# file -i app.js

app.js: text/plain; charset=utf-8

文件是utf-8,內容也是utf-8,所以原則上應該是沒有問題的。


另一個需要注意的是header,所以我在app.js上加上下列:

res.header("Content-Type", "application/json; charset=utf-8");

但是response的中文還是亂碼,最後發現是我的ssh client的問題。


因為Cloud上沒有辦法輸入中文,所以我是先在Windows的vs code編輯好後再複製程式碼貼到Cloud上。

我使用的是xshell來連線Cloud,需要在「檔案」->「內容」,找到「終端機」的設定頁,將編碼改為UTF-8

這樣貼上程式碼時才會是UTF-8,重啟cloud上的node.js後中文就可以正常顯示了。

ubuntu 18.04 安裝nginx與certbot

 記錄自己安裝及設定的過程,原本想以Docker來安裝,結果certbot一直無法成功安裝,會出現PID 0的錯誤。

雖然在Docker上已經加上--privileged 的參數,依然無法解決,只好放棄使用Docker Container來安裝。

我目前共有兩個API Service:coding1.test.com(10.0.10.7):3333、coding2.test.com(10.0.10.7):5555

先在DNS上設定好coding1.test.com、coding2.test.com

安裝的順序是先安裝nginx,再把nginx的設定完成並啟用,再安裝certbot

啟用certbot時會自動修改nginx的設定檔,這樣就不必手動修改。

1、更新一下apt

$ sudo apt update

2、安裝nginx

$ sudo apt-get install nginx

3、安裝完後,應該會自動啟動nginx,我是用netstat看port 80是否被佔用

$ sudo netstat -tulpn | grep :80

tcp 0  0 0.0.0.0:80  0.0.0.0:*   LISTEN  4648/nginx: master 

或是利用下列指令:

$ ps -ef |grep nginx

... nginx: master process /usr/sbin/nginx -g daemon on; master_process on;

... nginx: worker process

... nginx: worker process

另外也可以啟用ngx_http_stub_status_module來監控loding/status,參考文件:

http://nginx.org/en/docs/http/ngx_http_stub_status_module.html


4、nginx的start/stop/restart

sudo systemctl start nginx 

sudo systemctl stop nginx 

sudo systemctl restart nginx


5、修改nginx config

查看/etc/nginx/nginx.conf內容:

有一行include /etc/nginx/conf.d/*.conf; 表示會載入副檔名為.conf的設定


新增configure file

$ sudo cd /etc/nginx/conf.d

$ sudo vi coding1.conf


coding1.conf的內容如下:

server {

    listen       80;

    server_name  coding1.test.com;

location / {

proxy_pass   http://10.0.10.7:3333;

    }

}


其中listen是要監聽的port;proxy_pass是反向代理的設定,

換句話就是當連線到coding1.test.com:80時會自動轉向10.0.10.7:3333

再新建一個coding2.conf,內容格式大致一樣


讓nginx重新載入configure file

$ nginx -s reload


6、測試反向代理是否成功

$ sudo crul http://coding1.test.com

如出現設定的首頁內容就是正確


7、依照官方文件安裝snap、certbot:

https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx


目前最新版已無法利用apt install certbot,改以snapd來管理

$ sudo apt update

$ sudo apt install snapd


更新snapd到最新版本

$ sudo snap install core; sudo snap refresh core


安裝certbot

$ sudo snap install --classic certbot

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot


certbot有多種方式,可以自動/手動取得憑證,我選擇自動取得,

因為我是用nginx,所以加上--nginx讓certbot修改設定

$ sudo certbot --nginx

8、測試

$ sudo curl https://coding1.test.com

利用Node.js建立Https協定服務

因為有些外掛模組需要有https才能啟用,所以需要建立一個https Node.js。

https預設是443 port,傳輸過程中會加密,所以需要有CA憑證,而CA有Signed CA和Self-Signed CA,
前者憑證可被Root CA認證,適用於商業性質,但是通常需要付費,瀏覽器會標示綠標,也就是安全的網站;
後者不需Root CA認證,以自行發行憑證的方式進行,但是會被瀏覽器視為不安全的網站。

我因為只需要開發中有https的服務,所以採取簡單的方式,方式如下:


1、建立certificate檔案

產生RSA加密的私鑰,-out代表輸出私鑰的檔名,1024代表私鑰長度,如需更安全可以設定2048。
# openssl genrsa -out privatekey.pem 1024

建立憑證要求,-new為表示要產生CSR(certificate signing request),-key為讀取的私鑰,後面為私鑰檔,無指定則會產生一把新的私鑰。
用產生的私鑰產生一把用來生成證書的鑰匙。
# openssl req -new -key privatekey.pem -out csrreq.csr

X.509是一種公開金鑰(PKI) 的電信通訊標準,所以我們利用X.509產生一個CA簽證的憑證。
-days:生效的期限,預設為30天
-in:CSR憑證檔名
-signkey:私鑰檔
-out:產生的憑證檔名
# openssl x509 -req -days 9999 -in csrreq.csr -signkey privatekey.pem -out ca.pem


2、編輯JS如以下的檔案

const fs = require('fs');
const https = require('https');
const express = require('express');
const app = express();

//讀取憑證及金鑰
const prikey = fs.readFileSync('privatekey.pem', 'utf8');
const cert = fs.readFileSync('csrreq.pem', 'utf8');

//建立憑證及金鑰
const credentials = {
    key: prikey,
    cert: cert
};

https.createServer(credentials, app).listen(403, function() {
    console.log('https server listening on port 403');
});


Python3建立簡單的http server

因為需要測試Web API,所以利用python 3來建立一個簡單的http server,並傳回字串,程式如下,配合Docker還真的蠻方便的。
from http.server import HTTPServer, BaseHTTPRequestHandler

class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        if (self.path == "/"):
            self.send_response(200)
            self.send_header('Content-type','text/html')
            self.send_header('Access-Control-Allow-Origin','*')
            self.end_headers()
            self.wfile.write("我是首頁".encode()) #轉成二進位
            
        if (self.path == "/get_info"):           
            self.send_response(200)
            self.send_header('Content-type','application/json')
            self.send_header('Access-Control-Allow-Origin','*')
            self.end_headers()
            self.wfile.write("資訊頁測試.encode()) #轉成二進位
           
httpd = HTTPServer(('0.0.0.0', 80), SimpleHTTPRequestHandler)
httpd.serve_forever()

Google Blogger。自訂網域啟用HTTPS

Gooogle Blogger終於可以在自訂網域上使用HTTPS了,以往Blogger只允許自己的網域啟用HTTPS,可是我就是想用自己的網域名稱,如今終於開放自訂網域的HTTPS,啟用HTTPS後,安全性就更上一層樓了。

在「設定」-->「基本」頁面中,找到「HTTPS」,並將選項改為「是」
「HTTPS」重新導向我也把它改為「是」,這個選項的作用是無論使用者以HTTP或HTTPS連到我的網站,一律會以HTTPS的方式呈現,也就是說如果選擇「否」,則使用者以HTTP連線時,我的網站也會以HTTP的方式來回應,而不會以HTTPS來回應


設定完成後,等待一小段時間就系統完成設定後就可以了,當然之前在搜尋引擎內的HTTP網頁還是可以連接,不會失效

設定Github Webhook來自動更新Openshift v3 程式

今天測試紅帽(Red Hat)新一代PaaS公共雲平臺OpenShift V3, 設定完Node.js的服務後,又在GitHub Fork出Node.js的測試程式碼,接著依照文件上設定Webhook來讓GitHub可以自動更新我在OpenShift上的程式碼。

在嘗試一些錯誤之後,現在記錄一下自己成功的步驟:

在Openshift上我的專案中選擇Builds,再點選「Configuration」,按下「GitHub Webhook URL」旁的ICON圖示來複製URL或直接複製URL。



接著到GitHub的repository上選擇「Settings」



進入Setting之後,在左邊選擇「Webhooks」,在「Payload URL」處把上述複製的URL貼上,並且在「Content type」處選擇「application/json」


儲存後,可以回到Setting頁,再點一下「Webhooks」,可以發現已經新建了一個Webhook,如下圖,有綠色的勾勾表示成功,之後只要在GitHub有更新程式時,就會自動更新到Openshift。



在Goolge部落格用google code prettify讓程式碼在網頁中區隔

常常在別人的部落格內看到程式碼會有方框來做為區隔,這樣可以讓瀏覽更直覺。
本來想自己寫CSS來達成功能,沒有到早就有這樣的功能可以套用。
在看了一些方法之後,我自己選擇google code prettify來使用,原因是簡單、簡潔。

如何在Blogger中加入「繼續閱讀」(Read more)

Google的Blogger預設首頁會把文章所有的內容顯示出來,遇到較長文章的時候,後面的文章就會被排到非常下面的位置,如果可以快速預覽部份內容,對文章有興趣的人再自行點進去閱讀全文,對使用者的操作體驗是比較好的做法。如下圖整篇文章都顯示出來,首頁就會變得很長。



Blogger早在數年前已提供「繼續閱讀」(Read more)的功能,在編輯文章的區塊,工具列上有一個插入的功能如下圖,將它插入想要中斷的位置,就可以在首頁中顯示中斷位置以上的文字或圖片,並自動加入「繼續閱讀」(Read more),因為可以自己控制想要在首頁上顯示的方式,避免一句話被從中間截掉,所以這是最簡單、也是比較好的做法。




但是我的文章已經有好幾百篇,而且之前也沒有用上述的方法,如今要一篇一篇修正,就覺得全身無力。其實也可以用Javascript的方式,為我們自動加入「繼續閱讀」(Read more)的功能,不過只能限制字數,也就難免會有語句斷行的現象。
首先來到設計模式,選擇「範本」,再選擇「編輯HTML」



接下來就會看見密密麻麻的程式碼,我是將程式碼全部複製到Notepad++編輯器上,也可以用自己習慣的文書編輯器,方便後續的修改。



在Notepad++上按「Ctrl + F」開啟搜尋字串功能,找到字串 <data:post.body/> ,將所有找到的字串都取代成下列的程式碼

<!-- Auto Read More Body Start -->
<b:if cond='data:blog.url == data:blog.homepageUrl'>
<b:if cond='data:blog.pageType == &quot;index&quot;'>
<div expr:id='&quot;summary&quot; + data:post.id'><data:post.body/></div>
<script type='text/javascript'>createSummaryAndThumb(&quot;summary<data:post.id/>&quot;,&quot;<data:post.url/>&quot;,&quot;<data:post.title/>&quot;);</script>
<span class='jump-link' style='float:right;'><a expr:href='data:post.url' expr:title='data:post.title'><data:post.jumpText/></a></span>
</b:if></b:if>
<b:if cond='data:blog.pageType == &quot;item&quot;'><data:post.body/></b:if>
<b:if cond='data:blog.pageType == &quot;static_page&quot;'><data:post.body/></b:if>
<div style='clear: both;'/> <!-- clear for photos floats -->
<!-- Auto Read More in Body End -->

再按「Ctrl + F」,找到字串 </head>,在 </head> 之前加上下列的程式碼

<!-- Auto Read More Body Script Start -->
<script type='text/javascript'>
post_no_pic_sum = 300;
post_pic_sum = 200;
pic_h = 220;
pic_w = 300;
</script>
<script type='text/javascript'>
//<![CDATA[
function removeHtmlTag(t,e){if(-1!=t.indexOf("<")){for(var n=t.split("<"),i=0;i<n.length;i++)-1!=n[i].indexOf(">")&&(n[i]=n[i].substring(n[i].indexOf(">")+1,n[i].length));t=n.join("")}for(e=e<t.length-1?e:t.length-2;" "!=t.charAt(e-1)&&-1!=t.indexOf(" ",e);)e++;return t=t.substring(0,e-1),t+"..."}function createSummaryAndThumb(t,e,n){var i=document.getElementById(t),m="",r=i.getElementsByTagName("img"),s=post_no_pic_sum;r.length>=1&&(m='<span class="posts-thumb" style="float:left; margin-right: 10px;"><a href="'+e+'" title="'+n+'"><img src="'+r[0].src+'" width="'+pic_w+'px" height="'+pic_h+'px" /></a></span>',s=post_pic_sum);var g=m+"<div>"+removeHtmlTag(i.innerHTML,s)+"</div>";i.innerHTML=g}
//]]>
</script>
<b:if cond='data:blog.pageType != &quot;static_page&quot;'>
<b:if cond='data:blog.pageType != &quot;item&quot;'>
<style type='text/css'>
.post-footer {display: none;}
.jump-link  {float: right; }
.jump-link a {text-decoration: none; }
</style>
</b:if>
</b:if>
<!-- Auto Read More Body Script End -->

其中有幾個地方可以稍做修改:
post_no_pic_sum = 300;  –> 這裡是指文章內沒有夾帶圖片時要顯示的字數
post_pic_sum = 200;  -> 這裡是指文章內有夾帶圖片時要顯示的字數
pic_h = 220;  -> 圖片的高度
pic_w = 300;  -> 圖片的寬度
完成後,將程式碼複製到Blogger的編輯HTML上,按下「儲存範本」就可以試著檢視成果。



Blogger預設是用「Read more」來表示繼續閱讀,如果想要修改這段文字的話,可以依下列的方式:
1、開啟「版面配置」
2、在「Blog Posts」的區塊上,點選「編輯」
3、修改 Read more 成自己想要呈現的文字





Bootstrap固定置頂及置底的測試範例

除了jQuery Mobile之外,最近接觸到由Twitter釋出的Bootstrap前端框架工具。
Bootstrap是一個很簡潔,直覺,強大的前端框架,可以讓網頁或行動網頁開發更快速更簡單。

因為jQuery Mobile可以指定header與footer,所以也試著讓Bootstrap也可以置頂與置底。
Bootstrap本身就有提供置頂及置底的的函數:navbar-fixed-top、navbar-fixed-bottom

試著寫一個範例如下,之後會再一邊學習一邊分享心得。

 <!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
        <meta name="format-detection" content="telephone=no">
        <meta name="msapplication-tap-highlight" content="no">
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
        <link href="css/bootstrap.min.css" rel="stylesheet">
        <title>TEST</title>
    </head>
    <!-- 因為置頂會把內容蓋住,所以必須在body設定padding-top的寬度-->
    <!-- navbar-fixed-top預約會佔用50px的空間 -->
    <body style="padding-top:70px;">    
        <!-- Bootstrap需要使用jQuery,所以第一個引入 -->
        <script src="js/jquery-2.1.1.min.js"></script>
        <script src="js/bootstrap.min.js"></script>
        <script src="js/onduty.js"></script>
        <script type="text/javascript" src="cordova.js"></script>
        
        <!-- 巡覽置頂,會固到頂部 -->
        <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
            <div class="container">
                <div class="row" style="padding:0px">
                    <a href="#" class="btn btn-default btn-lg btn-block" >
                        頂部
                    </a>
                </div>
            </div>
        </nav>
                
        <div class="container-fluid">
            <div class="row">
                <p>話說一百八十年前, 
                    比現在的武林更加混亂, 
                    武林中人死傷無數, 
                    永無寧日。此時有一位貌似書生的人, 
                    約四大門派之主與劍尊在峰頂上談判, 
                    談判經過了三天三夜, 
                    四大門派之主與劍尊為了自己的權力, 
                    圴不肯和解, 
                    到了第四天,這名書生終於按奈不住, 
                    說道:「難道只有武力才能解決嗎?」 
                    ,眾人一致認同。只見書生運起內力, 
                    雙手一揮,一套神功應然而出, 
                    擊碎了兩百里外的峰頂,內力之強, 
                    眾人目瞪口呆,無不訝異,
                   同語「武林至尊在此」,於是同意和解, 
                    換來百年的和平。</p>
            </div>
        </div>
        
        <!-- 巡覽置底 -->
        <nav class="navbar navbar-default navbar-fixed-bottom" role="navigation">
            <div class="container">
                <div class="row" >
                <div class="col-xs-6" style="padding:0px" >
                    <a href="#" class="btn btn-default btn-lg btn-block" >
                        設定
                    </a>
                </div>
                
                <div class="col-xs-6" style="padding:0px">
                    <a href="#" class="btn btn-default btn-lg btn-block">
                        說明
                    </a>
                </div>
            </div>
            <div class="row" >
                <div class="col-xs-6" style="padding:0px" >
                    <a href="#" class="btn btn-default btn-lg btn-block" >
                        設定2
                    </a>
                </div>
                
                <div class="col-xs-6" style="padding:0px">
                    <a href="#" class="btn btn-default btn-lg btn-block">
                        說明2
                    </a>
                </div>
            </div>
            </div>
        </nav>
        
    </body>
</html>

Openshift用mysqldump備份MySQL

因為我在新建一個gears時,啟用了Scalable功能,所以要安裝phpMyAdmin時出現了錯誤:


所以就只能以SSH登入並以mysqldump這個指令的方式備份MySQL的資料,
但是Openshift對於MySQL的資訊是參數的方式表示,所以必須使用參數來取代MySQL的設定值。
$OPENSHIFT_MYSQL_DB_HOST:MySQL的Hostname
$OPENSHIFT_MYSQL_DB_PORT:MySQL使用的Port
$OPENSHIFT_MYSQL_DB_USERNAME:帳號
$OPENSHIFT_MYSQL_DB_PASSWORD:密碼

例如我要備份database的名稱為blogger,備份檔名為backup.bk,完整指令如下(同一行):
mysqldump -h $OPENSHIFT_MYSQL_DB_HOST -P $OPENSHIFT_MYSQL_DB_PORT
-u $OPENSHIFT_MYSQL_DB_USERNAME --password="$OPENSHIFT_MYSQL_DB_PASSWORD"
blogger > backup.bk

上述指令執行完成後,當然還要用SFTP把backup.bk下載下來才行。

SFTP與SSH可以參考我的文章:
OpenShift 設定SFTP上傳下載檔案

openshift 如何設定SSH登入管理


TimelineJS 用時間來說故事

網站:http://timeline.knightlab.com/

只需一個Google試算表及四個步驟就可以製作一個以時間來說故事的腳本。
TimelineJS是以時間軸為主軸,讓我們可以設計在某些時間點上發生的故事,
例如:2006年結婚、2007年寶寶出生、2008年買房子等事件。

因為需要使用Google試算表,所以我們必須要有一個Google的帳號,
這部份直接到Google就可以申請一個免費的帳號。

步驟的第一步是開啟Google試算表的範本如下圖按下「Google Spreadsheet Template ],

登入Google後,就會開啟試算表,試算表的第一行每個欄位都是都意義,不能隨意更改名稱及位置,
但是第二行開始就是我們的故事設計的地方,把事件發生的日期、原由、備註等,
輸入相對應的欄位,每一行就是一個事件。

完成試算表的設計之後,要把試算表發佈到網路上如下圖:


試算表發佈完成之後,在「連結」的頁面上會有一串網址,把它複製下來。

回到TimelineJS的網頁上,在第三個步驟的「Google」貼上剛剛複製的網址。
下面還有其他的選項可以選擇,依自己的需求選擇就行,也可以全部依照預設值。

最後的第四個步驟就是把方框內的iframe語法複製起來,貼到我們自己網頁的HTML上就可以了。

這是預設範本製作出來的故事截圖

SUNO歌詞試做