【问题标题】:Google App Script API cannot authenticate "Request contains an invalid argument"Google App Script API 无法验证“请求包含无效参数”
【发布时间】:2019-02-23 04:30:46
【问题描述】:

我几乎在使用谷歌自己网站上的示例

https://developers.google.com/apps-script/api/how-tos/execute

示例python脚本的相关部分复制如下

from __future__ import print_function
from googleapiclient import errors
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file as oauth_file, client, tools

def main():
    """Runs the sample.
    """
    SCRIPT_ID = 'ENTER_YOUR_SCRIPT_ID_HERE'

    # Setup the Apps Script API
    SCOPES = 'https://www.googleapis.com/auth/script.projects'
    store = oauth_file.Storage('token.json')
    creds = store.get()
    if not creds or creds.invalid:
        flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
        creds = tools.run_flow(flow, store)
    service = build('script', 'v1', http=creds.authorize(Http()))


if __name__ == '__main__':
    main()

我收到以下错误

  File "test.py", line 67, in <module>
    main()
  File "test.py", line 22, in main
    service = build('script', 'v1', http=creds.authorize(Http()))
  File "C:\Users\pedxs\Anaconda2\lib\site-packages\googleapiclient\_helpers.py", line 130, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "C:\Users\pedxs\Anaconda2\lib\site-packages\googleapiclient\discovery.py", line 232, in build
    raise e
googleapiclient.errors.HttpError: <HttpError 400 when requesting https://www.googleapis.com/discovery/v1/apis/script/v1/rest returned "Request contains an invalid argument.">

就在一周前,我有这个确切的代码工作。第 22 行使用发现构建功能,据我了解,它正在向 Google 的 API 身份验证器服务器“https://www.googleapis.com/discovery/v1/apis/script/v1/rest”发送凭据。我怀疑这是谷歌方面的问题,因为即使他们的示例代码也不起作用。

我已尝试创建新的 Google Cloud Platform 并获取新的 credentials.json 文件。我还尝试使用其他电子邮件帐户进行身份验证。

【问题讨论】:

  • 我认为这可能对您的情况有用。 stackoverflow.com/questions/54818256/…
  • @Tanaike。那么这种身份验证方法似乎不再有效?您是否找到了另一种可行的方法?
  • 有几种方法。 1.在Quickstart使用授权脚本。 2.如果您想在问题中使用脚本,请将http = credentials.authorize(httplib2.Http())service = discovery.build('script', 'v1', http=http)修改为service = build('script', 'v1', credentials=creds)。这在herehere 进行了讨论。
  • 我遇到的问题与原始问题完全相同。我的脚本已经运行了将近 2 年,现在我在没有进行其他更改的情况下遇到了同样的错误。谷歌方面有什么变化吗?
  • @Tanaike 您应该将其发布为答案

标签: python google-api-python-client oauth2client google-apps-script-api


【解决方案1】:

我遇到了同样的错误。

我在 1 年多前使用过该代码。

但突然间我从 2 月 23 日起就无法使用了。

所以我采用了另一种方法,我使用了 oauth2 的 post 请求。

我认为您需要更新您的 Google 服务帐户。

我认为范围 ui 会有所改变...

祝你好运!

■python代码

from oauth2client import client

def request_to_gas():
    credentials = client.OAuth2Credentials(
        access_token=None,
        client_id={your_client_id},
        client_secret={your_client_secret},
        refresh_token={your_refresh_token},
        token_expiry=None,
        token_uri=GOOGLE_TOKEN_URI,
        user_agent=None,
        revoke_uri=GOOGLE_REVOKE_URI)

    credentials.refresh(httplib2.Http())  # refresh the access token


    my_url = "your_google_apps_script_web_url" 
    myheaders = {'Authorization': 'Bearer {}'.format(credentials.access_token),
                 "Content-Type": "application/json"
                 }
    response = requests.post(my_url,
                  data=json.dumps({
                                   'localdate' : '2019/02/23 12:12:12'}),
                  headers=myheaders
                  )

添加精简代码并作为网络应用发布。

■谷歌应用程序脚本代码

function doPost(e) {
  var params = JSON.parse(e.postData.getDataAsString());  // ※
  var value = params.localdate;  // get python code -- 2019/02/23 12:12:12

  // here is your google apps script api
  do_something();

  var output = ContentService.createTextOutput();
  output.setMimeType(ContentService.MimeType.JSON);
  output.setContent(JSON.stringify({ message: "success!" }));

  return output;
}

【讨论】:

  • 太棒了,这哥们太棒了!
【解决方案2】:

在你的情况下,有两种模式。

模式一:

使用authorization script at Quickstart

示例脚本:

from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

def main():
    # Setup the Apps Script API
    SCOPES = ['https://www.googleapis.com/auth/script.projects', 'https://www.googleapis.com/auth/drive']

    creds = None
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'client_secret.json', SCOPES)
            creds = flow.run_local_server()
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)
    service = build('script', 'v1', credentials=creds)

    scriptId = "### script ID ###"  # Please set this
    request = {"function": "myFunction", "parameters": ["sample"], "devMode": True}
    response = service.scripts().run(body=request, scriptId=scriptId).execute()
    print(response)


if __name__ == '__main__':
    main()

模式 2:

如果您想在您的问题中使用该脚本,请按如下方式修改您的脚本。 herehere 对此进行了讨论。

示例脚本:

from __future__ import print_function
from googleapiclient.discovery import build
from oauth2client import file as oauth_file, client, tools

def main():
    SCOPES = ['https://www.googleapis.com/auth/script.projects', 'https://www.googleapis.com/auth/drive']

    store = oauth_file.Storage('token.json')
    creds = store.get()
    if not creds or creds.invalid:
        flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
        creds = tools.run_flow(flow, store)
    service = build('script', 'v1', credentials=creds)

    scriptId = "### script ID ###"  # Please set this
    request = {"function": "myFunction", "parameters": ["sample"], "devMode": True}
    response = service.scripts().run(body=request, scriptId=scriptId).execute()
    print(response)


if __name__ == '__main__':
    main()

GAS端示例脚本:

function myFunction(e) {
  return "ok: " + e;
}

结果:

您可以从以上两个脚本中检索以下响应。

{
  "response": {
    "@type": "type.googleapis.com/google.apps.script.v1.ExecutionResponse",
    "result": "ok: sample"
  },
  "done": True
}

注意:

在我的环境中,我可以确认以上两种模式都可以使用。但是,如果在您的环境中,没有使用这些,我很抱歉。

【讨论】:

  • 这解决了我的问题,关键是将凭据传递给 build(),而不是授权的 http 对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-12
  • 2023-03-29
  • 2020-01-06
  • 2019-01-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多