我正在尝试将项目卡插入时间轴,并将图像作为附件。
如果我尝试插入一个项目,那就顺利了:
def notify_card(my_user, card=None):
payload = card
headers = {'Content-Type': 'application/json',
'Authorization': 'Bearer {0}'.format(my_user.mirror_access_token)}
url = OAUTH_API_BASE_URL + '/mirror/v1/timeline'
r = requests.post(url, data=payload, headers=headers)
if r.status_code == 401:
new_access_token = __refresh_token(my_user.mirror_refresh_token)
__create_or_update_user(access_token=new_access_token, refresh_token=user_vademecum.mirror_refresh_token)
headers = {'Content-Type': 'application/json',
'Authorization': 'Bearer {0}'.format(new_access_token)}
r = requests.post(url, data=payload, headers=headers)
这样可行,将卡插入时间线。
现在出现问题,当我想上传图片时:
# Send media
import os
module_dir = os.path.dirname(__file__) # get current directory
file_path = os.path.join(module_dir, 'bodegon.jpg')
file = {'bodegon.jpg': ('bodegon.jpg', open(file_path, 'rb'), 'image/jpg')}
headers = {
'Authorization': 'Bearer {0}'.format(my_user.mirror_access_token)}
url = OAUTH_API_BASE_URL + 'upload/mirror/v1/timeline?uploadType=multipart'
r = requests.post(url, data={"message": {"bundleId": "0000001"}}, files=file, headers=headers)
print r.text
此代码返回错误消息:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "badContent",
"message": "Media type 'application/octet-stream' is not supported. Valid media types: [image/*, audio/*, video/*]"
}
],
"code": 400,
"message": "Media type 'application/octet-stream' is not supported. Valid media types: [image/*, audio/*, video/*]"
}
}
如果我手动设置内容类型:
headers = {'content-type': 'image/jpg',
'Authorization': 'Bearer {0}'.format(my_user.mirror_access_token)}
返回此消息:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "required",
"message": "Required"
}
],
"code": 400,
"message": "Required"
}
}
另外,我已尝试将媒体发送到此网址:
https://www.googleapis.com/upload/mirror/v1/timeline?uploadType=media
而不是
https://www.googleapis.com/upload/mirror/v1/timeline?uploadType=multipart
要使用简单上传进行上传: https://developers.google.com/glass/media-upload
我做错了什么?
答案 0 :(得分:2)
使用您提供的代码,请求将生成一个大致类似的请求主体:
--{boundary}
Content-Disposition: form-data; message="message"
bundleId
--{boundary}
Content-Disposition: form-data; name="bodegon.jpg"
{file contents}
--{boundary}--
请注意,您为bundleId
指定的ID不会显示。这意味着你可能希望它是JSON编码的数据,正如@Prison在他的回答中所暗示的那样。根据您的问题进一步判断,您需要为上传的文件部分提供Content-Type
。这可以这样解决:
import json
r = requests.post(url, files={"message": (, json.dumps({"bundleId": "0000001"}, 'application/json'), 'file': ('filename.jpg', file, 'image/jpeg')}, headers=headers)
headers
是您指定的原始字典。
此外,如果您要上传非常大的文件,您可能需要考虑不单独使用请求。该文件将完整加载到内存中。在这种情况下,您很可能希望流式传输上传。你可以这样使用requests-toolbelt:
import requests
from requests_toolbelt import MultipartEncoder
import json
fields = {
'message': (, json.dumps({'bundleId': '0000001'}, 'application/json'),
'file': ('filename.jpg', file, 'image/jpeg')
}
encoder = MultipartEncoder(fields)
headers = {
'Authorization': 'Bearer <your token>',
'Content-Type': encoder.content_type
}
r = requests.post(url, data=encoder, headers=headers)
这将处理数据编码并允许将数据流传输到服务器。
注意我没有使用文档检查表单部分的名称,因此使用'file'
可能不正确。我鼓励你自己调查一下。
答案 1 :(得分:1)
对于初学者,您可能需要考虑使用Google Client Library for Python。它包含了处理Mirror APIs以及执行Media Uploads的一般情况的具体方法。
如果您只是尝试使用附件创建时间轴项目,这可能是最简单的。请参阅https://developers.google.com/glass/v1/reference/timeline/insert#examples上的示例,然后单击Python选项卡。
如果您真的开始直接使用HTTP方法,则需要明确为什么要使用简单上传方法(uploadType = media)与多部分上传方法(uploadType = multipart)。简单上传需要您还调用timeline.attachment来指定附件的元数据,而多部分版本允许您同时上传两者。
使用简单方法,您应该能够使用image / jpeg的内容类型和包含图像数据的正文进行POST。这很简单。可以这么说。
使用multipart方法,您必须处理多种内容类型。您拥有整体的内容类型,其类型为&#34;多部分相关&#34;并包括有关每个部分之间的边界标记的信息。每个部分也都有一个内容类型 - 第一部分是&#34; application / json&#34;并包含元数据,而第二部分的类型为&#34; image / jpeg&#34;并包含图像体。它可能看起来像这样:
POST /upload/mirror/v1/timeline?uploadType=multipart HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer <your_auth_token>
Content-Type: multipart/related; boundary="foo_bar_baz"
Content-Length: <number_of_bytes_in_entire_request_body>
--foo_bar_baz
Content-Type: application/json; charset=UTF-8
{
"text": "Hello world!"
}
--foo_bar_baz
Content-Type: image/jpeg
<JPEG data>
--foo_bar_baz--
你需要自己建立这个身体。