用 Google Sheet 作 JSON 資料來源,解決 403 或 404 錯誤

之前作的一個專案有把 Google Sheet 當作 JSON 資料來源來使用,最近收到該網站沒有正常顯示資料,才發現原來今年 8 月 (2021年) Google 已經停用Sheets API v3 了

使用舊的API網址會出現 404 錯誤,並且回傳的訊息如下:

The Sheets v3 API has been turned down.

file

並附上一篇文章簡單告訴你 v4 API有多麼的強大,叫你趕快換掉你的 v3 API
Migrate your apps to use the latest Sheets API version—turning down v3 API by 2020

原本這個專案的需求很簡單,就是把行政人員在 Excel(就是google sheet) 上輸入的資料能漂亮的呈現在網站上給使用者觀看。

就從使用上的差異來說,v4 v3 除了 api 的 hostname 不一樣之外,v4 對API存取有更安全的限制,要額外申請 API金鑰來作為參數才能使用

不過我的情境上本身就是公開資料,此外v4 API又新又強大的功能我完全都不在意,反正只要符合原始需求中拿到表格中全部的資料,讓網站能正常顯示就可以收工了。

反而期待若前端來使用 API 能否讓網址列中避免出現原始資料的 google sheet Id 那就更好了,可惜沒看到這個功能

https://spreadsheets.google.com/feeds/list/你的google sheet Id/1/public/values?alt=json
https://sheets.googleapis.com/v4/spreadsheets/<你的google sheet Id>?key=<你的API key>&includeGridData=true

關於 404 錯誤

如果朋友你還在使用 v3 API 的設定方式,例如以下格式:

https://spreadsheets.google.com/feeds/list/<你的google sheet Id>/1/public/values?alt=json

因為google已經給 v3 API 判死刑了,所以一定會出現 404錯誤,網路上那些起死回生的設定方式都不能用了(我試過了),唯一的解決辦法就是升級到v4。

如果朋友你已經在使用 v4 API 仍發生 404錯誤,則檢查你的網址是否正確或網址中帶入的Google Sheet Id是否正確

https://sheets.googleapis.com/v4/spreadsheets/<你的google sheet Id>

圖片中紅線的部分是這份 Google Sheet 的 Id,不包含/符號,請檢查 Id 是否正確
file

關於 403 錯誤

403錯誤發生在你沒有這份 Sheet 的存取權限,請確認以下兩點,缺一不可

  1. Google Sheet的共用請設定為知道這個連結的使用者皆可檢視
  2. 網址參數加上key=<你的API金鑰>

網址格式:

https://sheets.googleapis.com/v4/spreadsheets/<你的google sheet Id>?key=<你的API金鑰>

檢查你的 Sheet Id 能否正確取得資料

Google 提供的說明文件中,右側有提供測試 API 的功能,只要在登入 Google 帳號的情況下,輸入你的 Sheet Id 就能知道是否能正確地取得資料

這邊我準備了範例Google Sheet Id 是 1xcFQ0WI6G8CvDW3MVrqPfPXL1HewACB5koy_kgT4kyg
file

輸入Id,並將includeGridData選為true代表要拿到的資料包含表格內的內容
file

第一次使用時會跳出是否提供讀取權限給Google API Exploer,就按確定
file

下方就可以看到回應結果
file

JSON完整回應內容我貼在文章最後面

接下來講取得金鑰的方式

取得金鑰

請前往Google Cloud Platform建立一個新專案,並在專案中取得金鑰(有些地方把金鑰翻譯成憑證)

點選紅色框住的地方來切換專案或是建立新專案
file

輸入專案名稱後按建立(專案名稱不能用中文…)
file

建立完成後,會看到資訊主業,選擇 API總覽
file

在API總覽最下方篩選中可以看到能選擇的API類型,若沒有Google Sheet API的選項,請點選上方的啟用API和服務
file

找到(或用搜尋)Google Sheets API後,點選並按啟用
file
file

點選建立憑證
file

選擇Google Sheets API ->應用程式資料 -> 最後一個選項我這邊沒有要搭配其他服務所以選 -> 完成
file

接下來進到這個畫面,按上方的建立憑證
file

選擇API金鑰
file

這樣你就可以拿到API金鑰可以測試了
file

API金鑰的權限設定

設定完成後,你可能看到這個API金鑰有驚嘆號圖示,代表你沒有設定此金鑰限制,當其他人得知你的金鑰時,就可以透過API拿到資料
file

好的做法是對金鑰加以限制,例如限制能使用的伺服器網址或IP
file

並且限制此金鑰只能使用在 Google Sheet 上面,並且儲存就大功告成了
file

參考資料
https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/get

https://hsuan9522.medium.com/google-sheet-v4-api-efdec9a96bf3

```json
{
  "spreadsheetId": "1xcFQ0WI6G8CvDW3MVrqPfPXL1HewACB5koy_kgT4kyg",
  "properties": {
    "title": "API測試資料",
    "locale": "zh_TW",
    "autoRecalc": "ON_CHANGE",
    "timeZone": "Asia/Hong_Kong",
    "defaultFormat": {
      "backgroundColor": {
        "red": 1,
        "green": 1,
        "blue": 1
      },
      "padding": {
        "top": 2,
        "right": 3,
        "bottom": 2,
        "left": 3
      },
      "verticalAlignment": "BOTTOM",
      "wrapStrategy": "OVERFLOW_CELL",
      "textFormat": {
        "foregroundColor": {},
        "fontFamily": "arial,sans,sans-serif",
        "fontSize": 10,
        "bold": false,
        "italic": false,
        "strikethrough": false,
        "underline": false,
        "foregroundColorStyle": {
          "rgbColor": {}
        }
      },
      "backgroundColorStyle": {
        "rgbColor": {
          "red": 1,
          "green": 1,
          "blue": 1
        }
      }
    },
    "spreadsheetTheme": {
      "primaryFontFamily": "Arial",
      "themeColors": [
        {
          "colorType": "ACCENT5",
          "color": {
            "rgbColor": {
              "red": 1,
              "green": 0.42745098,
              "blue": 0.003921569
            }
          }
        },
        {
          "colorType": "ACCENT2",
          "color": {
            "rgbColor": {
              "red": 0.91764706,
              "green": 0.2627451,
              "blue": 0.20784314
            }
          }
        },
        {
          "colorType": "ACCENT3",
          "color": {
            "rgbColor": {
              "red": 0.9843137,
              "green": 0.7372549,
              "blue": 0.015686275
            }
          }
        },
        {
          "colorType": "ACCENT4",
          "color": {
            "rgbColor": {
              "red": 0.20392157,
              "green": 0.65882355,
              "blue": 0.3254902
            }
          }
        },
        {
          "colorType": "TEXT",
          "color": {
            "rgbColor": {}
          }
        },
        {
          "colorType": "BACKGROUND",
          "color": {
            "rgbColor": {
              "red": 1,
              "green": 1,
              "blue": 1
            }
          }
        },
        {
          "colorType": "ACCENT1",
          "color": {
            "rgbColor": {
              "red": 0.25882354,
              "green": 0.52156866,
              "blue": 0.95686275
            }
          }
        },
        {
          "colorType": "ACCENT6",
          "color": {
            "rgbColor": {
              "red": 0.27450982,
              "green": 0.7411765,
              "blue": 0.7764706
            }
          }
        },
        {
          "colorType": "LINK",
          "color": {
            "rgbColor": {
              "red": 0.06666667,
              "green": 0.33333334,
              "blue": 0.8
            }
          }
        }
      ]
    }
  },
  "sheets": [
    {
      "properties": {
        "sheetId": 0,
        "title": "工作表1",
        "index": 0,
        "sheetType": "GRID",
        "gridProperties": {
          "rowCount": 1000,
          "columnCount": 26
        }
      },
      "data": [
        {
          "rowData": [
            {
              "values": [
                {
                  "userEnteredValue": {
                    "stringValue": "老闆"
                  },
                  "effectiveValue": {
                    "stringValue": "老闆"
                  },
                  "formattedValue": "老闆",
                  "effectiveFormat": {
                    "backgroundColor": {
                      "red": 1,
                      "green": 1,
                      "blue": 1
                    },
                    "padding": {
                      "top": 2,
                      "right": 3,
                      "bottom": 2,
                      "left": 3
                    },
                    "horizontalAlignment": "LEFT",
                    "verticalAlignment": "BOTTOM",
                    "wrapStrategy": "OVERFLOW_CELL",
                    "textFormat": {
                      "foregroundColor": {},
                      "fontFamily": "Arial",
                      "fontSize": 10,
                      "bold": false,
                      "italic": false,
                      "strikethrough": false,
                      "underline": false,
                      "foregroundColorStyle": {
                        "rgbColor": {}
                      }
                    },
                    "hyperlinkDisplayType": "PLAIN_TEXT",
                    "backgroundColorStyle": {
                      "rgbColor": {
                        "red": 1,
                        "green": 1,
                        "blue": 1
                      }
                    }
                  }
                },
                {
                  "userEnteredValue": {
                    "stringValue": "王XX"
                  },
                  "effectiveValue": {
                    "stringValue": "王XX"
                  },
                  "formattedValue": "王XX",
                  "effectiveFormat": {
                    "backgroundColor": {
                      "red": 1,
                      "green": 1,
                      "blue": 1
                    },
                    "padding": {
                      "top": 2,
                      "right": 3,
                      "bottom": 2,
                      "left": 3
                    },
                    "horizontalAlignment": "LEFT",
                    "verticalAlignment": "BOTTOM",
                    "wrapStrategy": "OVERFLOW_CELL",
                    "textFormat": {
                      "foregroundColor": {},
                      "fontFamily": "Arial",
                      "fontSize": 10,
                      "bold": false,
                      "italic": false,
                      "strikethrough": false,
                      "underline": false,
                      "foregroundColorStyle": {
                        "rgbColor": {}
                      }
                    },
                    "hyperlinkDisplayType": "PLAIN_TEXT",
                    "backgroundColorStyle": {
                      "rgbColor": {
                        "red": 1,
                        "green": 1,
                        "blue": 1
                      }
                    }
                  }
                }
              ]
            },
            {
              "values": [
                {
                  "userEnteredValue": {
                    "stringValue": "經理"
                  },
                  "effectiveValue": {
                    "stringValue": "經理"
                  },
                  "formattedValue": "經理",
                  "effectiveFormat": {
                    "backgroundColor": {
                      "red": 1,
                      "green": 1,
                      "blue": 1
                    },
                    "padding": {
                      "top": 2,
                      "right": 3,
                      "bottom": 2,
                      "left": 3
                    },
                    "horizontalAlignment": "LEFT",
                    "verticalAlignment": "BOTTOM",
                    "wrapStrategy": "OVERFLOW_CELL",
                    "textFormat": {
                      "foregroundColor": {},
                      "fontFamily": "Arial",
                      "fontSize": 10,
                      "bold": false,
                      "italic": false,
                      "strikethrough": false,
                      "underline": false,
                      "foregroundColorStyle": {
                        "rgbColor": {}
                      }
                    },
                    "hyperlinkDisplayType": "PLAIN_TEXT",
                    "backgroundColorStyle": {
                      "rgbColor": {
                        "red": 1,
                        "green": 1,
                        "blue": 1
                      }
                    }
                  }
                },
                {
                  "userEnteredValue": {
                    "stringValue": "林XX"
                  },
                  "effectiveValue": {
                    "stringValue": "林XX"
                  },
                  "formattedValue": "林XX",
                  "effectiveFormat": {
                    "backgroundColor": {
                      "red": 1,
                      "green": 1,
                      "blue": 1
                    },
                    "padding": {
                      "top": 2,
                      "right": 3,
                      "bottom": 2,
                      "left": 3
                    },
                    "horizontalAlignment": "LEFT",
                    "verticalAlignment": "BOTTOM",
                    "wrapStrategy": "OVERFLOW_CELL",
                    "textFormat": {
                      "foregroundColor": {},
                      "fontFamily": "Arial",
                      "fontSize": 10,
                      "bold": false,
                      "italic": false,
                      "strikethrough": false,
                      "underline": false,
                      "foregroundColorStyle": {
                        "rgbColor": {}
                      }
                    },
                    "hyperlinkDisplayType": "PLAIN_TEXT",
                    "backgroundColorStyle": {
                      "rgbColor": {
                        "red": 1,
                        "green": 1,
                        "blue": 1
                      }
                    }
                  }
                }
              ]
            },
            {
              "values": [
                {
                  "userEnteredValue": {
                    "stringValue": "員工"
                  },
                  "effectiveValue": {
                    "stringValue": "員工"
                  },
                  "formattedValue": "員工",
                  "effectiveFormat": {
                    "backgroundColor": {
                      "red": 1,
                      "green": 1,
                      "blue": 1
                    },
                    "padding": {
                      "top": 2,
                      "right": 3,
                      "bottom": 2,
                      "left": 3
                    },
                    "horizontalAlignment": "LEFT",
                    "verticalAlignment": "BOTTOM",
                    "wrapStrategy": "OVERFLOW_CELL",
                    "textFormat": {
                      "foregroundColor": {},
                      "fontFamily": "Arial",
                      "fontSize": 10,
                      "bold": false,
                      "italic": false,
                      "strikethrough": false,
                      "underline": false,
                      "foregroundColorStyle": {
                        "rgbColor": {}
                      }
                    },
                    "hyperlinkDisplayType": "PLAIN_TEXT",
                    "backgroundColorStyle": {
                      "rgbColor": {
                        "red": 1,
                        "green": 1,
                        "blue": 1
                      }
                    }
                  }
                },
                {
                  "userEnteredValue": {
                    "stringValue": "小明"
                  },
                  "effectiveValue": {
                    "stringValue": "小明"
                  },
                  "formattedValue": "小明",
                  "effectiveFormat": {
                    "backgroundColor": {
                      "red": 1,
                      "green": 1,
                      "blue": 1
                    },
                    "padding": {
                      "top": 2,
                      "right": 3,
                      "bottom": 2,
                      "left": 3
                    },
                    "horizontalAlignment": "LEFT",
                    "verticalAlignment": "BOTTOM",
                    "wrapStrategy": "OVERFLOW_CELL",
                    "textFormat": {
                      "foregroundColor": {},
                      "fontFamily": "Arial",
                      "fontSize": 10,
                      "bold": false,
                      "italic": false,
                      "strikethrough": false,
                      "underline": false,
                      "foregroundColorStyle": {
                        "rgbColor": {}
                      }
                    },
                    "hyperlinkDisplayType": "PLAIN_TEXT",
                    "backgroundColorStyle": {
                      "rgbColor": {
                        "red": 1,
                        "green": 1,
                        "blue": 1
                      }
                    }
                  }
                }
              ]
            }
          ],
          "rowMetadata": [
            {
              "pixelSize": 100
            },....
          ]
        }
      ]
    }
  ],
  "spreadsheetUrl": "https://docs.google.com/spreadsheets/d/1xcFQ0WI6G8CvDW3MVrqPfPXL1HewACB5koy_kgT4kyg/edit"
}
Facebook留言板