You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Teams Bot中FileInfoCard的SharePoint内容URL无效问题求助

Teams Bot PDF文件上传后FileInfoCard链接无效问题排查

问题描述

基于Teams File Upload Bot示例开发Teams Bot,尝试传输PDF文件时,流程已成功返回FileConsentCard及后续的FileInfoCard,但点击FileInfoCard提供的content URL链接时,无法查看或下载文件。上传过程无异常提示,OneDrive中显示已创建文件,但文件为空或不可用。需排查链接无效的原因,确认是否为权限问题。

相关代码

private CompletableFuture<Void> sendFileCard(
        TurnContext turnContext, String filename, long filesize
    ) { 
        
        Map<String, String> consentContext = new HashMap<>();
        consentContext.put("filename", filename);

        FileConsentCard fileCard = new FileConsentCard();
        fileCard.setDescription("This is the file I want to send you");
        fileCard.setSizeInBytes(filesize);
        fileCard.setAcceptContext(consentContext);
        fileCard.setDeclineContext(consentContext);

        Attachment asAttachment = new Attachment();
        asAttachment.setContent(fileCard);
        asAttachment.setContentType(FileConsentCard.CONTENT_TYPE);
        asAttachment.setName(filename);     

        Activity reply = turnContext.getActivity().createReply();
        reply.setAttachments(Collections.singletonList(asAttachment));

        return turnContext.sendActivityBlind(reply);
    }
private CompletableFuture<ResultPair<String>> upload(
        FileConsentCardResponse fileConsentCardResponse
    ) {
        AtomicReference<ResultPair<String>> result = new AtomicReference<>();       
        
        return CompletableFuture.runAsync(() -> {
            Map<String, String> context = (Map<String, String>) fileConsentCardResponse
                .getContext();
            File filePath = new File("files", context.get("filename"));
            HttpURLConnection connection = null;

            try {               
                
                URL url = new URL(fileConsentCardResponse.getUploadInfo().getUploadUrl());
                connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("PUT");
                connection.setDoOutput(true);
                connection.setRequestProperty("Content-Length", Long.toString(filePath.length()));
                connection.setRequestProperty(
                    "Content-Range",
                    String.format("bytes 0-%d/%d", filePath.length() - 1, filePath.length())
                );              

                try (
                    FileInputStream fileStream = new FileInputStream(filePath);
                    OutputStream uploadStream = connection.getOutputStream()
                ) {
                    byte[] buffer = new byte[4096];
                    int bytes_read;
                    while ((bytes_read = fileStream.read(buffer)) != -1) {                      
                        uploadStream.write(buffer, 0, bytes_read);
                    }                   
                }

                result.set(new ResultPair<String>(true, null));
            } catch (Throwable t) {              
                result.set(new ResultPair<String>(false, t.getLocalizedMessage()));
            } finally {                 
                if (connection != null) {
                    connection.disconnect();
                }
            }
        })
            .thenApply(aVoid -> result.get());
    }
private CompletableFuture<Void> fileUploadCompleted(
        TurnContext turnContext, FileConsentCardResponse fileConsentCardResponse
    ) {
        FileInfoCard downloadCard = new FileInfoCard();
        downloadCard.setUniqueId(fileConsentCardResponse.getUploadInfo().getUniqueId());
        downloadCard.setFileType(fileConsentCardResponse.getUploadInfo().getFileType());

        Attachment asAttachment = new Attachment();
        asAttachment.setContent(downloadCard);
        asAttachment.setContentType(FileInfoCard.CONTENT_TYPE);
        asAttachment.setName(fileConsentCardResponse.getUploadInfo().getName());        
        
        asAttachment.setContentUrl(fileConsentCardResponse.getUploadInfo().getContentUrl());

        Activity reply = MessageFactory.text(
            String.format(
                "<b>File uploaded.</b> Your file <b>%s</b> is ready to download",
                fileConsentCardResponse.getUploadInfo().getName()
            )
        );
        reply.setTextFormat(TextFormatTypes.XML);
        reply.setAttachment(asAttachment);

        return turnContext.sendActivityBlind(reply);
    }

问题原因与修复方案

核心原因

  1. 错误的分片上传头设置:代码中强制添加Content-Range请求头,该头用于分片上传场景,但当前是完整文件上传,会导致OneDrive无法正确解析文件数据,最终生成空文件。
  2. 缺少上传结果验证:未检查HTTP请求的响应状态码,即使上传失败(如文件不存在、权限不足),仍会标记上传成功,掩盖真实问题。
  3. 文件存在性未验证:直接读取指定路径的文件,未判断文件是否存在、是否可读,若文件缺失则上传空数据。

修复步骤

  1. 移除Content-Range请求头
    删除上传代码中以下行:

    connection.setRequestProperty(
        "Content-Range",
        String.format("bytes 0-%d/%d", filePath.length() - 1, filePath.length())
    );
    
  2. 添加响应状态检查
    在文件流写入完成后,添加响应码验证:

    int responseCode = connection.getResponseCode();
    if (responseCode != HttpURLConnection.HTTP_OK && responseCode != HttpURLConnection.HTTP_CREATED) {
        throw new IOException("上传失败,响应码:" + responseCode);
    }
    
  3. 添加文件合法性验证
    在读取文件前,校验文件状态:

    if (!filePath.exists() || !filePath.canRead()) {
        throw new FileNotFoundException("文件不存在或无法读取:" + filePath.getAbsolutePath());
    }
    
  4. 确认文件类型正确
    确保发送FileConsentCard时,文件类型设置为application/pdf,保证OneDrive能正确识别文件格式。

验证方法

修复代码后重新部署Bot,发起PDF上传请求,检查OneDrive中文件是否有实际内容,再点击FileInfoCard链接确认能否正常访问。

内容的提问来源于stack exchange,提问作者lfdevjmp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 20:03:13