星期二, 10月 28, 2025

[GAS] LineBot 取得使用者名稱

Line 有提供 profile API 可以取得使用者名稱,實務情況常見於使用者加入好友當下觸發,把 userID 和 displayName 紀錄進好友資訊

profile API
https://api.line.me/v2/bot/profile/{userId}
Response

呼叫成功 status code 會回傳 200 並回傳下列 json
{
  "displayName": "LINE taro",
  "userId": "U4af4980629...",
  "language": "en",
  "pictureUrl": "https://profile.line-scdn.net/ch/v2/p/uf9da5ee2b...",
  "statusMessage": "Hello, LINE!"
}
其中 pictureUrl 和 statusMessage 要使用者有設定才會有該資訊

Error Response

呼叫後的 status code 有 400 和 404
  • 400:不是有效的 userID
  • 404 則有下列四種可能
    • userID 不存在
    • 使用者沒有同意授權可以取得 profile 資訊
    • 該使用者沒有加 LineBot 為好友
    • 該使用者封鎖 LineBot
// 400 json
{
  "message": "The value for the 'userId' parameter is invalid"
}

// 404 json
{
  "message": "Not found"
}

Google Apps Script .gs Code
function doPost(e) {

  try {

    let contents = JSON.parse(e.postData.contents);
    let event = contents.events[0];
    let userID = event.source.userId

    // 加 LineBot 為好友
    if (event.type === 'follow') {
      let profile = getProfile(userID);
      let displayName = profile.displayName;
      WriteLog([new Date(), '加入好友', userID, displayName])
      return;
    }

    // 發送文字訊息
    if (
      event.type === "message" &&
      event.message &&
      event.message.type === "text") {

      let text = contents.events[0].message.text;
      WriteLog([new Date(), "文字訊息", userID, text]);
      return;
    }

    WriteLog([new Date(), "無對應事件"]);
    
  } catch (e) {
    WriteLog([new Date(), "錯誤訊息:", e.toString()]);
  }
}

function getProfile(userId) {

  // 從 PropertiesService 取出 LineChannelAccessToken
  let lineChannelAccessToken = getProperties("LineChannelAccessToken");
  let url = `https://api.line.me/v2/bot/profile/${userId}`;

  let options = {
    'method': 'GET',
    'headers': {
      'Authorization': 'Bearer ' + lineChannelAccessToken,
      'Content-Type': 'application/json'
    },
    'muteHttpExceptions': true
  };

  try {

    let response = UrlFetchApp.fetch(url, options);
    let responseCode = response.getResponseCode();
    let responseText = response.getContentText();

    if (responseCode === 200) {
      return JSON.parse(responseText);
    } else {
      WriteLog([new Date() , `Get Profile API 呼叫失敗。Code: ${responseCode}, Response: ${responseText}`]);
      return null;
    }

  } catch (e) {

    WriteLog([new date() , `執行 UrlFetchApp 發生錯誤: ${e.toString()}`])
    return null;
  }
}

function WriteLog(logData) {

  if (!logData || !Array.isArray(logData)) {
    Logger.log("WriteLog 錯誤:傳入的參數不是有效的陣列。");
    return;
  }

  try {

    // 從 PropertiesService 取出 SheetID 和 SheetName
    let sheetID = getProperties("SheetID");
    let sheetName = getProperties("SheetName");

    let ss = SpreadsheetApp.openById(sheetID);
    let sheet = ss.getSheetByName(sheetName)

    if (!sheet) {
      Logger.log(`WriteLog 錯誤:找不到名稱為 ${SHEET_NAME} 的工作表。`);
      return false;
    }

    sheet.appendRow(logData);
    Logger.log(`成功寫入 Log: ${logData.join(', ')}`);
  } catch (e) {
    Logger.log("WriteLog 寫入失敗: " + e.toString());
  }

}

function getProperties(key) {
  let scriptProperties = PropertiesService.getScriptProperties();
  let properties = scriptProperties.getProperties();
  return properties[key];
}
使用者把 LineBot 加入好友並傳送文字訊息測試
UrlFetchApp.fetch muteHttpExceptions 參數

預設值為 false,以該範例為例來說明就是當 status code 為 400 或 404 時,GAS 會停止運行,設定為 true 會回傳 status code 來表示
 
設定為 false,回傳 400 時 GAS 停止運行,是停止運行而不是拋出 exception,try catch 是無法阻止停止運行的,如下圖
設定為 true 可以判斷 status code 並把錯誤訊息顯示出來,當然也可以寫進 Log 內

沒有留言:

張貼留言