Python调用SharePoint API分块上传遇serverRelativeUrl参数错误
问题核心原因
你遇到的serverRelativeUrl参数错误,主要由三个问题导致:
- 服务器相对路径格式不完整且错误提前编码
- 对整个API请求URL进行了不必要的全编码,导致SharePoint无法识别API路径
- 文件偏移量(fileOffset)计算逻辑错误
具体修复步骤
1. 修正服务器相对路径格式
getfilebyserverrelativeurl要求的参数是完整的站点级服务器相对路径,格式应为:
/sites/{site_name}/Shared Documents/{folder_name}/{file_name}
注意:
- 不要提前对路径进行URL编码(比如不要把空格换成
%20),SharePoint会自动处理路径中的特殊字符 - 如果是根站点(非
/sites子站点),路径开头去掉/sites/{site_name}即可
2. 禁止对整个API URL编码
你代码中url = urllib.parse.quote(file_url)是错误操作,会把API路径中的/、(等字符编码成%2F、%28,导致SharePoint无法识别正确的API端点。直接使用拼接好的file_url作为请求路径即可。
3. 修正fileOffset计算逻辑
- startupload:不需要指定fileOffset,接口会自动处理第一块数据
- continueupload:fileOffset是已上传的总字节数,即
CHUNK_SIZE * (chunk_count - 1)(比如第2块的offset是1*CHUNK_SIZE) - finishupload:fileOffset必须等于文件总大小,无论最后一块是否填满CHUNK_SIZE
4. 修正分块计数逻辑
用math.ceil(file_size / CHUNK_SIZE)计算总块数,避免浮点数导致循环次数错误。
修改后的完整代码
import os import uuid import http.client import math CHUNK_SIZE = 10 * 1024 * 1024 # 10MB分块,可根据需求调整 SHAREPOINT_HOST = "your-tenant.sharepoint.com" # 替换为你的SharePoint域名 def uploadFile(bearer_token: str, tenant_name: str, site_name: str, folder_name: str, file_name: str) -> str: with open(file_name, "rb") as file: file_size = os.stat(file_name).st_size big_file = file_size > CHUNK_SIZE if big_file: headers = { 'Authorization': f'Bearer {bearer_token}', 'Accept': 'application/json;odata=verbose', 'Content-Type': 'application/octet-stream' } upload_id = uuid.uuid4() chunk_count = 1 total_chunks = math.ceil(file_size / CHUNK_SIZE) continue_upload = True # 构建正确的服务器相对路径 server_relative_url = f"/sites/{site_name}/Shared Documents/{folder_name}/{os.path.basename(file_name)}" while continue_upload: big_file_chunk = file.read(CHUNK_SIZE) chunk_length = len(big_file_chunk) if chunk_count == total_chunks: # 最后一块,执行finishupload file_offset = file_size api_path = f"/sites/{site_name}/_api/web/getfilebyserverrelativeurl('{server_relative_url}')/finishupload(uploadId=guid'{upload_id}',fileOffset={file_offset})" continue_upload = False elif chunk_count == 1: # 第一块,执行startupload api_path = f"/sites/{site_name}/_api/web/getfilebyserverrelativeurl('{server_relative_url}')/startupload(uploadId=guid'{upload_id}')" else: # 中间块,执行continueupload file_offset = CHUNK_SIZE * (chunk_count - 1) api_path = f"/sites/{site_name}/_api/web/getfilebyserverrelativeurl('{server_relative_url}')/continueupload(uploadId=guid'{upload_id}',fileOffset={file_offset})" # 直接使用api_path,不要编码整个URL conn = http.client.HTTPSConnection(SHAREPOINT_HOST) conn.request("POST", api_path, big_file_chunk, headers) resp = conn.getresponse() resp_content = resp.read() print(chunk_count, " -- ", resp_content) # 检查响应状态码,非200/201则抛出异常或处理 if resp.status not in (200, 201, 202): raise Exception(f"Upload failed at chunk {chunk_count}: {resp_content.decode('utf-8')}") chunk_count += 1 return resp_content.decode("utf-8")
额外注意事项
- 确保
SHAREPOINT_HOST是你的租户域名(比如contoso.sharepoint.com),不要包含https:// - 分块大小建议设置为10MB到100MB之间,过大可能导致请求超时
- 每次请求后检查响应状态码,及时捕获上传失败的情况
内容的提问来源于stack exchange,提问作者d.rat
相关产品推荐
相关产品推荐

