使用Graph API和Java上传大文件至SharePoint遇generalException错误求助
1. 检查目标路径的文件夹层级是否存在
小文件上传接口(content().put())会自动创建不存在的父文件夹,但大文件上传的创建会话接口不会自动递归创建层级文件夹。如果destinationWithDate中的父文件夹(如2024/July/FolderA/FolderB)不存在,会触发模糊的generalException。
解决步骤:
- 拆分文件路径和文件名,先递归创建所有父文件夹
- 再基于已存在的父文件夹创建上传会话
示例代码:
// 拆分路径:分离父文件夹和文件名 String parentPath = destinationWithDate.substring(0, destinationWithDate.lastIndexOf("/")); String fileName = destinationWithDate.substring(destinationWithDate.lastIndexOf("/") + 1); // 递归创建父文件夹(不存在则创建) String[] folderLevels = parentPath.split("/"); String currentPath = ""; for (String folder : folderLevels) { currentPath += "/" + folder; try { // 尝试获取文件夹,不存在则抛出异常 graphServiceClient.drives() .byDriveId(drive.getId()) .items() .byDriveItemId("root:" + currentPath + ":") .get(); } catch (ApiException e) { // 创建当前层级的文件夹 DriveItem newFolder = new DriveItem(); newFolder.name = folder; newFolder.folder = new Folder(); // 基于上级文件夹创建 String parentFolderPath = currentPath.substring(0, currentPath.lastIndexOf("/")); graphServiceClient.drives() .byDriveId(drive.getId()) .items() .byDriveItemId("root:" + parentFolderPath + ":") .children() .post(newFolder); } } // 基于已存在的父文件夹创建上传会话 UploadSession uploadSession = graphServiceClient.drives() .byDriveId(drive.getId()) .items() .byDriveItemId("root:/" + parentPath + ":") .itemWithPath(fileName) .createUploadSession() .post(uploadSessionRequest);
2. 捕获更详细的错误信息
默认的ApiException仅返回generalException,需要手动获取Graph API返回的具体响应内容,定位根本原因(如权限不足、文件冲突、路径格式错误等)。
示例代码:
try { UploadResult<DriveItem> uploadResult = largeFileUploadTask.upload(maxAttempts, callback); } catch (ApiException e) { // 打印详细错误信息 System.out.println("状态码: " + e.getResponseStatusCode()); if (e.getResponseHeaders() != null) { e.getResponseHeaders().forEach((key, value) -> System.out.println(key + ": " + value)); } if (e.getResponseBody() != null) { System.out.println("响应体: " + new String(e.getResponseBody())); } e.printStackTrace(); }
3. 配置上传会话的冲突处理策略
如果目标文件已存在,大文件上传会话默认会报错,而小文件上传可能默认覆盖。需要显式设置冲突处理规则,保持行为一致。
示例代码:
CreateUploadSessionPostRequestBody uploadSessionRequest = new CreateUploadSessionPostRequestBody(); DriveItemUploadableProperties itemProps = new DriveItemUploadableProperties(); itemProps.name = fileName; // 设置覆盖已存在的文件(可选值:replace/rename/fail) itemProps.additionalDataManager().put("@microsoft.graph.conflictBehavior", new JsonPrimitive("replace")); uploadSessionRequest.item = itemProps;
4. 调整分片大小与请求超时
默认分片大小为5MB,若网络不稳定可能导致分片上传超时;同时检查客户端超时配置是否足够。
示例代码:
// 调整分片大小为10MB(最大不超过60MB) LargeFileUploadTask<DriveItem> largeFileUploadTask = new LargeFileUploadTask<>( graphServiceClient, uploadSession, fileStream, fileSize, DriveItem.class, 10 * 1024 * 1024 ); // 配置客户端超时时间 OkHttpClient httpClient = new OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .writeTimeout(60, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) .build(); GraphServiceClient graphServiceClient = GraphServiceClient.builder() .httpClient(httpClient) .authenticationProvider(authProvider) .build();
5. 确认权限范围有效性
确保应用/用户已授予Files.ReadWrite.All或Sites.ReadWrite.All权限,且权限已生效(管理员同意后需重新获取令牌)。
内容的提问来源于stack exchange,提问作者Megan
相关产品推荐
相关产品推荐

