Apps Script用Sheet生成動態網頁(11): 重構doGet()

在前10篇中我們建構了一個生成動態網頁的環境,背後使用sheet作為資料庫,可上傳html檔案,在透過doGet()將其顯示出來。然而在結合更多服務之後,諸如:上傳檔案,顯示檔案列表與縮圖、提供不同類型的檔案、提供註冊會員與確認信,導致doGet()內的判斷變得太多,用戶存取時間增加。這裡就是針對doGet()流程進行結構性的重構,減少判斷,提高伺服器回應速度。

重構後

善用javascript的object與接受任意型態的特性,doGet從原本臃腫的if-else簡化成5行

function doGet(req) {
let show = req.parameter['show'];
if (null == show) show = 'default';
let h = Handlers[show] || Handlers.default;
let output = h.func(req.parameter['name'], h.pass);
if (h.immediateRetrun) return output;
return output;
}

使用show參數來為各個功能進行分類,每一個功能都只會有一個對應的Handler進行處理,呼叫Handler的func就是呼叫處理單元,並會返回處理結果的輸出。如果找不到對應的分類則使用default的Handler。

因為各分類的功能可能會需要參數,所以name參數就是用來傳遞參數的,而Handler的pass部份則是處理該類需要用到的額外參數。

此外,還會看到handler還有immediateRetrun屬性,若設屬性為true時,會直接將Handler處理的結果output直接回覆給使用者。


對應的Handler及需要變動的功能getContentOfFile()和confirmRegistrationToken()都列在下方

function getContentOfFile(name, pass) {
let fileName = name + pass.subName;
let content = '';
try {
content = HtmlService.createHtmlOutputFromFile(fileName).getContent();
} catch (error) {
console.error(`找不到${fileName}`);
}
return ContentService.createTextOutput(content).setMimeType(pass.mimeType);
}

function confirmRegistrationToken(token) {
let content;
try {
let result = handleConfirm(token);
Logger.log(result);
content = '註冊確認成功';
} catch (error) {
Logger.log(error.stack);
content = '註冊確認失敗' + error.message;
}
return HtmlService.createHtmlOutput(content);
}

const TemplateFiles = {
default: 'index.html',
listFilesOfDrive: 'list_files_of_drive.html',
}

const Handlers = {
javascript: {
func: getContentOfFile,
immediateRetrun: true,
pass: { mimeType: ContentService.MimeType.JAVASCRIPT, subName: '.js' },
},
json: {
func: getContentOfFile,
immediateRetrun: true,
pass: { mimeType: ContentService.MimeType.JSON, subName: '.json' },
},
text: {
func: getContentOfFile,
immediateRetrun: true,
pass: { mimeType: ContentService.MimeType.TEXT, subName: '.txt' },
},
xml: {
func: getContentOfFile,
immediateRetrun: true,
pass: { mimeType: ContentService.MimeType.XML, subName: '.xml' },
},
default: {
func: () => HtmlService.createTemplateFromFile(TemplateFiles.default).evaluate()
},
filesInDrive: {
func: () => HtmlService.createTemplateFromFile(TemplateFiles.listFilesOfDrive).evaluate()
},
html: {
func: (name) => HtmlService.createHtmlOutput(getContentFromSheet(name))
},
confirmToken: {
func: confirmRegistrationToken,
immediateRetrun: true,
},
};


因為以上改動,所以使用連結的部份也需要調整,

1. 上傳HTML檔案的uploadHtmlFile()

return { name, url: getServerUrl() + '?show=html&name=' + name };

2. 註冊使用者的addUser()

const url = `${getServerUrl()}?show=confirmToken&name=${accessToken}`;

3. 使用者登入的連結 app.js.html

appendChildToBody(`您尚未登入,<a href="?show=html&name=登入會員">點此</a>登入`);

 

留言