iT邦幫忙

0

APP Script 無法動作

  • 分享至 

  • xImage

目前正在使用 Line Message API 串接 Google Sheet 的實作。
基本流程為:
使用者在 Line 群組傳送訊息 → 透過 Line Message API 傳送至 Google Sheet → 處理資料後回覆至原群組。

我目前嘗試了兩種方法:

方案一:

  • Line Message Webhook 使用 Make 平台串接,將訊息傳素至 Google Sheet
  • App Script 僅設定觸發條件試算表 - 文件內容變更時立即通知

方案二:拆分為兩個 .gs 程式碼檔案

  • 第一個檔案:Line Message Webhook,透過 App Script 網路應用程式部署,可成功將 Line 訊息寫入 Google Sheet
  • 第二個檔案:處理 Google Sheet 資料並將回覆訊息傳送至 Line 群組
  • 觸發指令設定成第二個檔案 並且一樣為試算表 - 文件內容變更時立即通知

然而,方案二無法順利執行完整流程(從使用者輸入到處理並回覆)。
目前狀況是:

  • 訊息可以正常寫入 Google Sheet
  • 手動執行處理程式碼時可以正常處理並傳送訊息至 Line
    可以看到有正常被觸發
    https://ithelp.ithome.com.tw/upload/images/20250212/20148353OQNDFzNn7N.jpg
    懇請各位前輩提供技術建議與解決方案,感謝。

[02/13]更
補上程式碼還有相關圖片。
另外後續我將兩段程式碼整和在一起 不使用觸發 單純部屬就可以正常執行
https://ithelp.ithome.com.tw/upload/images/20250213/20148353ec8QI7lSio.jpg
process_message.gs

// LINE Channel Access Token
const CHANNEL_ACCESS_TOKEN = "{token已先移除}";

// 主要處理函數
function processMessageAndSendToLine() {
  try {
    // 記錄開始日誌
    Logger.log("開始處理訊息並發送到 Line");
    
    // 從試算表獲取最後一列資料
    const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
    const lastRow = sheet.getLastRow();
    
    // 確保有資料
    if (lastRow <= 1) {
      Logger.log("試算表中沒有資料");
      return;
    }
    
    // 直接使用 D 欄位作為群組ID
    const groupId = sheet.getRange(lastRow, 4).getValue();
    
    // 使用 C 欄位作為訊息內容
    const message = sheet.getRange(lastRow, 3).getValue();
    
    Logger.log("群組ID: " + groupId);
    Logger.log("訊息內容: " + message);
    
    // 直接發送訊息到 Line
    const sendResult = sendLineMessage(CHANNEL_ACCESS_TOKEN, groupId, message);
    
    if (sendResult) {
      Logger.log("成功發送訊息到 Line");
    } else {
      Logger.log("發送 Line 訊息失敗");
    }
    
  } catch (error) {
    // 記錄任何錯誤
    Logger.log("處理訊息時發生錯誤: " + error.toString());
  }
}

function sendLineMessage(channelAccessToken, groupId, text) {
  try {
    const LINE_API_URL = 'https://api.line.me/v2/bot/message/push';
    
    const messages = [{
      type: "text",
      text: text
    }];
    
    const options = {
      method: 'post',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${channelAccessToken}`,
        'X-Line-Retry-Key': Utilities.getUuid()
      },
      payload: JSON.stringify({
        to: groupId,
        messages: messages
      }),
      muteHttpExceptions: true
    };
    
    const response = UrlFetchApp.fetch(LINE_API_URL, options);
    return response.getResponseCode() === 200;
  } catch (error) {
    Logger.log("發送 Line 訊息錯誤: " + error.toString());
    return false;
  }
}

// 手動觸發函數
function manualTrigger() {
  processMessageAndSendToLine();
}

webhook.gs

function doPost(e) {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName("工作表1");
  
  try {
    // 系統當前時間
    var currentTime = new Date().toLocaleString();
    
    // 解析 LINE 傳來的 JSON 資料
    var postData = JSON.parse(e.postData.contents);
    
    // 確保有事件資料
    if (postData.events && postData.events.length > 0) {
      var event = postData.events[0];
      
      // 取得所需資料
      var lineTime = new Date(parseInt(event.timestamp));
      var formattedTime = Utilities.formatDate(lineTime, Session.getScriptTimeZone(), "yyyy/MM/dd HH:mm:ss");
      var messageText = event.message ? event.message.text || "" : "";
      var groupId = event.source ? event.source.groupId || "" : "";
      var userId = event.source ? event.source.userId || "" : "";
      
      // 建立要寫入的資料陣列
      var rowData = [
        [currentTime, formattedTime, messageText, groupId, userId, e.postData.contents]
      ];
      
      // 取得最後一列的下一列
      var lastRow = sheet.getLastRow() + 1;
      
      // 明確指定要寫入的範圍(從A到F欄)
      var range = sheet.getRange(lastRow, 1, 1, 6);
      
      // 寫入資料
      range.setValues(rowData);
      
      // 設定儲存格格式(自動調整高度、文字換行等)
      range.setVerticalAlignment("top");
      range.setWrap(true);
    }
    
    // 回傳成功訊息給 LINE 平台
    return ContentService.createTextOutput(JSON.stringify({
      'status': 'success',
      'code': 200
    })).setMimeType(ContentService.MimeType.JSON);
    
  } catch(error) {
    // 發生錯誤時,將錯誤訊息寫入試算表
    var lastRow = sheet.getLastRow() + 1;
    var range = sheet.getRange(lastRow, 1, 1, 6);
    range.setValues([[
      currentTime,
      "",
      "ERROR: " + error.toString(),
      "",
      "",
      e.postData ? e.postData.contents : "No post data"
    ]]);
    
    // 回傳錯誤訊息給 LINE 平台
    return ContentService.createTextOutput(JSON.stringify({
      'status': 'error',
      'code': 500,
      'message': error.toString()
    })).setMimeType(ContentService.MimeType.JSON);
  }
}

function doGet(e) {
  return ContentService.createTextOutput("Webhook is working.");
}

觸發圖片
https://ithelp.ithome.com.tw/upload/images/20250213/20148353uDDgirEpUd.jpg

meebox iT邦新手 3 級 ‧ 2025-02-13 09:30:12 檢舉
可以把程式碼放上來嗎?
win895564 iT邦研究生 5 級 ‧ 2025-02-13 15:57:35 檢舉
已補上,感謝
.

1 個回答

0
Gary
iT邦好手 1 級 ‧ 2025-02-13 13:31:51

對於方案二給幾個方向建議,可能與觸發條件或權限有關,可以參考:

  1. 檢查Google Apps Script中文件內容變更的觸發器。確保設定的是修改而非新增。
  2. 確認觸發器是否與修改Google Sheet行動同步。可以手動觸發測試,看是否成功。
  3. 關於提到手動執行程式碼可正常執行,可能是自動化回應的執行權限有問題,檢查是否正確授權 Apps Script執行操作並回傳訊息。
  4. 最後觸發後訊息如果沒即時回應,可能處理時間延遲或處理邏輯上有瓶頸,特別針對需要與外部服務如:Line API 交換資訊。可考慮加入延遲或排程,讓訊息能被正確回應。
win895564 iT邦研究生 5 級 ‧ 2025-02-13 16:01:17 檢舉

感謝回復已補充相關程式碼跟圖片
1.目前為文件內容變更時立即通知
2.觸發器的部分有測試過在google sheet直接添加一筆資料是可以正常傳到line
3.想了解這個授權的部分該去哪裡確認,目前是一開始建立的時候 執行程式碼會有需要授權的頁面,已經有授權
4.這部分我在加入測試看看,感謝

Gary iT邦好手 1 級 ‧ 2025-02-14 10:00:30 檢舉
  1. 確認 Apps Script 觸發器類型
  • Simple Triggers:如 onEdit(e) 無法存取 Google API,可能導致錯誤。
  • Installable Triggers:需要使用者授權,可存取 Google API。
  1. 確認 Apps Script OAuth 授權
  • 檢查專案範圍權限Apps Script → 專案設定檢查是否包含所需API
  • 執行Apps Script觸發OAuth授權,或重啟Apps Script API
  1. 確認 Google Workspace 管理設定,API 存取權限控制允許 Apps Script 存取 Google API

  2. 確認外部 API 存取權限,Apps Script 網路未被公司防火牆或 Google 限制。

我要發表回答

立即登入回答