You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过JavaScript API写入Google Sheet失败,集成Google Identity Services仍无效

Google Sheets API 写入失败排查与修复

我能通过Google Sheet API正常读取表格数据,但无法写入。已经尝试集成Google Identity Services完成登录,写入功能还是不能正常工作,且已确认在console.cloud.google.com完成了相关配置,求技术帮助。

相关代码

<!DOCTYPE html>
<html>
<head>
</head>
<body>

<button id="authorize_button" onclick="handleAuthClick()">Authorize</button>
<button id="signout_button" onclick="handleSignoutClick()">Sign Out</button>
<pre id="content" style="white-space: pre-wrap;"></pre>
<form id="violationForm">
    <h3>Detention Report</h3>
    <label for="duration">Select Duration:</label>
    <select id="duration" name="duration">
        <option value="15">15 minutes</option>
        <option value="30">30 minutes</option>
    </select>
    <br><br>

    <label>Reasons for Report:</label>
    <ul>
        <li>
            <input type="checkbox" id="tardy" name="reason" value="tardy">
            <label for="followDirections">Tardy</label>
        </li>
        <li>
            <input type="checkbox" id="other" name="reason" value="Other">
            <label for="other">Other:</label>
            <input type="text" id="otherDescription" name="otherDescription" placeholder="Describe other reason">
        </li>
    </ul>
    <br>
    <input type="button" id="submitDetention" name="submitDetention" value="Submit Detention">
</form>

<script>
const CLIENT_ID = 'the client ID';
const SCOPES = 'https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email';
const discoveryUrl = 'https://sheets.googleapis.com/$discovery/rest?version=v4';
const redirectUri = 'https://thewebsiteImusing.com/callback';
const API_KEY = 'theAPIKey';
const SHEET_ID = 'theSheetID';
let tokenClient;
let gapiInited = false;
let gisInited = false;
var detentionStudents = []

////////////Authentication and Google API Specific Code///////////////
function gapiLoaded() {
    gapi.load('client', initializeGapiClient);
}
async function initializeGapiClient() {
    await gapi.client.init({
        apiKey: API_KEY,
    client_id: CLIENT_ID,
        discoveryDocs: [discoveryUrl],
        scope: SCOPES,
        redirect_uri: redirectUri,
    });
    gapiInited = true;
}

function gisLoaded() {
    tokenClient = google.accounts.oauth2.initTokenClient({
        client_id: CLIENT_ID,
        scope: SCOPES,
        callback: '', // defined later
    });
    gisInited = true;
}

function handleAuthClick() {
    tokenClient.callback = async (resp) => {
        if (resp.error !== undefined) {
            throw (resp);
        }
        document.getElementById('signout_button').style.visibility = 'visible';
        document.getElementById('authorize_button').innerText = 'Refresh';
        console.log('User signed in:', resp);
        // Continue with your logic after sign-in
    };

    if (gapi.client.getToken() === null) {
        // Prompt the user to select a Google Account and ask for consent to share their data
        // when establishing a new session.
        tokenClient.requestAccessToken({ prompt: 'consent' });
    } else {
        // Skip display of account chooser and consent dialog for an existing session.
        tokenClient.requestAccessToken({ prompt: '' });
    }
}

function handleSignoutClick() {
    const token = gapi.client.getToken();
    if (token !== null) {
        google.accounts.oauth2.revoke(token.access_token);
        gapi.client.setToken('');
        document.getElementById('authorize_button').innerText = 'Authorize';
        document.getElementById('signout_button').style.visibility = 'hidden';
    }
}

function fetchStudentIDs() {
// Define the name of the sheet
const sheetName = 'studentList';

// Clear the detentionStudents array if it's not empty
detentionStudents.length = 0;

// Load the Google Sheets API
gapi.load('client', initClient);

function initClient() {
    gapi.client.init({
        apiKey: API_KEY,
        discoveryDocs: 
['https://sheets.googleapis.com/$discovery/rest?version=v4'],
    }).then(function () {
        // Fetch the data from the sheet
        gapi.client.sheets.spreadsheets.values.get({
            spreadsheetId: SHEET_ID,
            range: `${sheetName}!A:A`,
        }).then(function (response) {
            const values = response.result.values;
            if (values && values.length > 0) {
                // Extract user IDs and store them in the detentionStudents array
                detentionStudents = values.map(row => row[0]);
                console.log('Student IDs retrieved:', detentionStudents);
                confirm('Student IDs retrieved:' + detentionStudents)
            } else {
                console.log('No data found in the sheet.');
            }
        }, function (error) {
            console.error('Error fetching data from the sheet:', error);
        });
    });
}
}



function submitDetentionRecord() {
    const rowData = ["John Doe", "today", "30", "tardy", "1st Period"];

    // Append values to the "detentionRecords" sheet
    appendValues(SHEET_ID, 'detentionRecords', 'RAW', [rowData], (response) => {
        console.log('Detention record submitted to Google Sheet:', response);
        // Optionally, you can clear the form or perform other actions after submission.
        alert(`The detention for ${currentStudent} was submitted`);
    });
}

function appendValues(spreadsheetId, range, valueInputOption, _values, callback) {
    let values = _values;
    const body = {
        values: values,
    };
    try {
        gapi.client.sheets.spreadsheets.values.append({
            spreadsheetId: spreadsheetId,
            range: range,
            valueInputOption: valueInputOption,
            resource: body,
        }).then((response) => {
            const result = response.result;
            console.log(`${result.updates.updatedCells} cells appended.`);
            if (callback) callback(response);
        });
    } catch (err) {
        console.error('Error appending values to Google Sheet:', err);
        alert('There was an error submitting the detention');
    }
}

// Attach the submitDetentionRecord function to the submit button

 
 
 
 document.getElementById('submitDetention').addEventListener('click', submitDetentionRecord);

</script>


<script async defer src="https://apis.google.com/js/api.js" onload="gapiLoaded()"></script>
<script async defer src="https://accounts.google.com/gsi/client" onload="gisLoaded()"></script>
</body>
</html>

排查与修复步骤

1. 确认权限与令牌绑定

  • 检查授权回调返回的权限范围:在handleAuthClick的回调里添加console.log('Granted scopes:', resp.scope),确认包含https://www.googleapis.com/auth/spreadsheets。
  • 授权成功后必须将令牌绑定到gapi客户端,否则写入请求会默认用API_KEY(仅只读)。修改handleAuthClick的回调:
tokenClient.callback = async (resp) => {
    if (resp.error !== undefined) {
        throw (resp);
    }
    // 新增:将授权令牌绑定到gapi客户端
    gapi.client.setToken({access_token: resp.access_token});
    document.getElementById('signout_button').style.visibility = 'visible';
    document.getElementById('authorize_button').innerText = 'Refresh';
    console.log('User signed in:', resp);
    console.log('Granted scopes:', resp.scope);
};

2. 修复写入请求的错误处理

原代码的try/catch无法捕获Promise异步错误,改用.catch()处理:

function appendValues(spreadsheetId, range, valueInputOption, _values, callback) {
    let values = _values;
    const body = {
        values: values,
    };
    gapi.client.sheets.spreadsheets.values.append({
        spreadsheetId: spreadsheetId,
        range: range,
        valueInputOption: valueInputOption,
        resource: body,
    }).then((response) => {
        const result = response.result;
        console.log(`${result.updates.updatedCells} cells appended.`);
        if (callback) callback(response);
    }).catch((err) => {
        console.error('Error appending values to Google Sheet:', err);
        alert('提交失败:' + err.message);
    });
}

3. 修正代码中的变量错误

submitDetentionRecord里的currentStudent未定义,会导致alert报错,替换为实际值:

alert(`The detention for John Doe was submitted`);

4. 核对控制台配置

  • 确认OAuth客户端ID的重定向URI和代码中的redirectUri完全一致(包括协议、域名、路径)。
  • 确认Google Sheets API已在控制台启用。
  • 如果应用未发布,检查测试用户是否已添加到OAuth同意屏幕的测试列表中。

内容的提问来源于stack exchange,提问作者chance holzwart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 07:37:02