pnp / pnpjs

Fluent JavaScript API for SharePoint and Microsoft Graph REST APIs
https://pnp.github.io/pnpjs/
Other
742 stars 302 forks source link

Getfilebyserverrelativeurl return corrupted file for .docx file #3024

Closed kaushalbcactus closed 5 hours ago

kaushalbcactus commented 2 months ago

Major Version

3.x

Minor Version Number

3.19.0

Target environment

NodeJS

Additional environment details

I am trying to fetch file from sharepoint but it is returning corrupted file. Related to my issue Similar issue raised earlier by me. I was trying to analyse and realised that it worked for txt files but returned corrupted file for .docx type of file.

Expected or Desired Behavior

Calling function should return non corrupted file in buffer

Observed Behavior

I am getting corrupted file for .docx file

Steps to Reproduce

import { spfi } from "@pnp/sp"; import "@pnp/sp/webs"; import "@pnp/sp/files"; import "@pnp/sp/folders";

const sp = spfi(...); const buffer: ArrayBuffer = await sp.web.getFileByServerRelativePath("/sites/dev/documents/Test.txt").getBuffer();

Please try below files:-

  1. Test_qerty (1).docx - I tried getText() and returned garbled text
  2. Test.txt - I tried getText() and returned proper text
patrick-rodgers commented 2 months ago

this is correct, docx files are not text files and getText renders the raw textual content of the file. It does not extract text or understand docx or any other format.

kaushalbcactus commented 2 months ago

Thanks @patrick-rodgers but retrieved buffer data issue still exists for me

  1. Please try both methods and check getserverrelativeurl returns different data
  2. `getFile: async function (headers, fileurl) {

    let responsePromise;
    if (Object.keys(headers).length) {
        const cred = {
        clientId: 'abc',
        clientSecret: 'abc',
        realm: 'abc'
        }
        const authtoken = await sprequest.getAuth('https://abc', cred);
        headers['Authorization'] = authtoken.headers.Authorization;
        responsePromise = got(fileurl, { headers });
    } else {
        responsePromise = got(fileurl);
    }
    const bufferPromise = responsePromise.buffer();
    const [response, buffer] = await Promise.all([responsePromise, bufferPromise]);
    return buffer;

    }`

  3. Use below method
  4. `import { spfi } from "@pnp/sp"; import "@pnp/sp/webs"; import "@pnp/sp/files"; import "@pnp/sp/folders";

const sp = spfi(...); const buffer: ArrayBuffer = await sp.web.getFileByServerRelativePath("/sites/dev/documents/Test.txt").getBuffer(); const flatArray = response.flat(2); const obj = common.getResponseArray(flatArray, 'Obj'); const buffer = Buffer.from(obj);`

  1. file Test_qerty (1).docx

We are passing this buffer data to another service where buffer from got works but buffer from this data fails and both buffer returns different length of data.

kaushalbcactus commented 1 month ago

Hi can anybody please assist in this?

kbeeveer46 commented 1 month ago

What are you trying to do with the file? Get the file so the user can download it in their browser? We use getFileByServerRelativePath but we use getBlob() instead of getBuffer(). I just tested your file and didn't have any issues downloading it. Also, could it be your upload code that's corrupting it and not the download? This is the code we use

Get file from SharePoint:

const blob = await spfi().using(SPFx(this.context)).web.getFileByServerRelativePath(document.relativeUrl).getBlob();
const success = await this.commonService.outputBlobToBrowser(blob, document.name);

Use the file-saver npm package to output it to the browser:

public async outputBlobToBrowser(blob: Blob, fileName: string): Promise<boolean>
    {
        try 
        {
            if (!blob?.size)
                return false;

            const fileSaver = await import(/* webpackChunkName: "fileSaver" */'file-saver');

            fileSaver.saveAs(blob, fileName);

            return true;
        }
        catch (error)
        {
            console.error("outputBlobToBrowser error: " + error);
            return false;
        }
    }

Upload: await sp.web.getFolderByServerRelativePath(path).files.addUsingPath(file.name, file, { Overwrite: true });

bcameron1231 commented 1 month ago

Just checking back, did @kbeeveer46 's example help you?

kaushalbcactus commented 4 weeks ago

Thanks @kbeeveer46 @bcameron1231! This works but realized that it causes issue when used with batch requests.

So, can you please guide if there any restriction to use with batch?

patrick-rodgers commented 3 weeks ago

@kaushalbcactus - you would need to explain "issue when used with batch requests" so we have some idea of what you are seeing.

bcameron1231 commented 5 hours ago

Closing this due to inactivity. If you continue to have issues please open a new issue, link to this issue, and provide any additional details available. Thanks!