Is it possible to directly parse a multipart/mixed response without needing to first convert it into a string?

My current challenge involves receiving a multipart/mixed response over HTTP that includes JSON data and PDFs in byte format. Due to Angular's limitations with handling such responses, I have resorted to converting the response into a string using the responseType: 'text' option.

To work with this data, I break down the response, extract the JSON, and transform the PDF data into a Blob as shown below:

let pdf: Blob = new Blob([new TextEncoder().encode(bytestring)], { type: 'application/pdf' });

The issue arises when attempting to create a download link for the PDF using window.URL.createObjectURL(pdf), resulting in a damaged file that cannot be opened.

I have verified that Angular utilizes UTF-8 encoding when turning the response into a string. Additionally, setting up a separate route allows me to request a single PDF independently with responseType: 'blob' which successfully downloads a functional PDF. Comparison between the original PDF and the damaged one at a byte level in VS Code reveals no noticeable differences.

Given my ability to transfer a working PDF separately but facing challenges within the multipart request, it appears that the conversion of a PDF to a string and back may be causing issues. Is there a solution that avoids transforming the PDF into a string?

Answer №1

After much exploration, I've cracked the code. The key lies in using responseType: 'blob' for the entire response and then converting it into both text and bytes. This allows you to parse JSON data, PDF headers, and build PDF files efficiently. Below is my functional Typescript implementation.

public async processMultipartData(multipartBody: Blob): Promise<MyMultipartResponse> {

    let bodyData: Uint8Array = new Uint8Array(await multipartBody.arrayBuffer());
    let bodyText: string = await multipartBody.text();
    
    // Extract file names from Content-Disposition Header.
    let filenames: RegExpMatchArray = bodyText.match(/filename.*\.pdf/gi)!; 
    let boundary: string = bodyText.substring(0, bodyText.indexOf('\n')).trim();
    
    let responseDataJson: string = bodyText.split(boundary)[1];
    // Parse the extracted JSON data into a JavaScript object.
    let responseData: MyJsonRepresentation = JSON.parse(responseDataJson.substring(responseDataJson.indexOf('{')));

    let encoder: TextEncoder = new TextEncoder();
    let startOfFile: Uint8Array = encoder.encode("%PDF");
    let endOfFile: Uint8Array = encoder.encode("%%EOF");

    let pdfData: Blob;
    let filename: string;
    let pdfFiles: MyPDFFile[] = [];
    let foundStart: Boolean = false;
    let filecontentStart: number = 2 * boundary.length + responseDataJson.length;

    scan: for(let i = filecontentStart; i < bodyData.length - endOfFile.length; i++) {

        if (!foundStart) {

            for (let j = 0; j < startOfFile.length; j++) {
                if (bodyData[i + j] != startOfFile[j])
                    continue scan;
            }

            filecontentStart = i;
            foundStart = true;
        }

        for (let j = 0; j < endOfFile.length; j++) {
            if (bodyData[i + j] != endOfFile[j])
                continue scan;
        }

        pdfData = multipartBody.slice(filecontentStart, i + endOfFile.length, 'application/pdf');
        filename = filenames.shift()!;

        // Store binary data, filename, and download link in a custom class.
        pdfFiles.push(new MyPDFFile(filename.substring(filename.indexOf('"') + 1), pdfData, window.URL.createObjectURL(pdfData)));
        foundStart = false;             
    }

    return new MyMultipartResponse(responseData, pdfFiles);
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Encountered a hiccup during the installation of ssh2-sftp-client on Next.js

I'm looking for a way to save uploaded files in my domain's storage using SFTP. I came across the multer-sftp package, but when I attempted to run the command yarn add multer-sftp ssh2-sftp-client, I encountered a strange error with the second pa ...

Utilize AngularJS directives within an Angular component for enhanced functionality

I'm currently in the process of enhancing an angularjs directive to integrate it into my angular component. I have successfully set up the hybrid (ng1 + ng2) environment and have also managed to inject angularjs services into Angular and utilize them ...

Encountered an issue while saving a blob in NativeScript: "Unable to convert object to [B at index

I have a Nativescript Angular application that is downloading a PDF from a Rails server in Blob Uint8Array format. When I attempt to save it, I encounter the following error: JS: /data/user/0/com.asset.management/files/result.pdf JS: ERROR Error: Uncaught ...

The component is unable to access the injected service from a separate module due to its null

In my Angular v6 project, there are 2 modules: app.module.ts, which includes the AppComponent and BoatComponent, and imports another module called draggable.module.ts. app.module.ts @NgModule({ declarations: [ AppComponent, BoatComponent ...

A guide to accessing an ngModel element within a reusable component

I have a specific ngModel component inside a reusable component that is not part of a form. I need to access it in order to make some changes, but when I try to do so using the code below, it returns undefined during OnInit. Can you advise me on how to pro ...

Double Calling of Angular Subscription

I am currently working with a series of observables that operate in the following sequence: getStyles() --> getPrices() Whenever a config.id is present in the configs array, getStyles() retrieves a style Object for it. This style Object is then passed ...

It appears that Stackblitz may have an outdated package.json file for older Angular projects, causing compatibility issues when running the project locally

Upon reviewing the package.json files for older Angular projects on Stackblitz, I have observed a pattern where Angular9 is listed under devDependencies while dependencies include older versions such as "@angular/core": "7.2.2" or "@angular/core": "6.1.10" ...

After upgrading from angular-cli version 4 to version 7, the npm installation process stops working

I have been working on transitioning my Angular4 project to Angular7. Here are the steps I took in order to make this conversion: I first uninstalled the older version of angular-cli Next, I installed the latest updated version of angular-cli However, up ...

Retrieving the previous and current URL in Angular 8

Need help setting variables prevUrl and currentUrl in Angular 8 by fetching previous and current URLs. The scenario involves two components - StudentComponent and HelloComponent. When transitioning from HelloComponent to StudentComponent, I face an issue. ...

Passing an event from onSubmit in React without using lambdas

Within our current project, the tslint rule jsx-no-lambda is in place. When attempting to capture event from onSubmit, this is how I typically write my code: public handleLogin = (event: React.FormEvent<HTMLFormElement>) => { event.preventDe ...

What is the best way to include text or a label on my Angular map without using a marker?

I am currently using the agm-map module in my angular project. I want to place a label or text at the center of a polygon on the map without using markers. How can I achieve this functionality in Typescript? I attempted to use the MapLabel Utility for thi ...

Unlock specific elements within the "sub-category" of a combined collection

If my union type is structured like this: type StateUpdate = { key: 'surname', value: string } | { key : 'age', value: number }; This setup is convenient because it allows me to determine the type of the value based on the key. Howev ...

Avoid running multiple YouTube views simultaneously within an AngularJS application

Currently, I have an Angularjs application that displays a list of Youtube videos utilizing the videogular node module. An issue has arisen where users can play multiple Youtube videos simultaneously, leading to potential violations of Youtube's poli ...

Fetching User Details Including Cart Content Upon User Login

After successfully creating my e-commerce application, I have managed to implement API registration and login functionalities which are working perfectly in terms of requesting and receiving responses. Additionally, I have integrated APIs for various produ ...

implementing a function to execute after making a successful $http.get request

I have implemented ngrx-store and am attempting to activate a spinner before making an HTTP call, and disabling it once the call has been completed. getInspectionDetails(order) { this.store.dispatch({ type: SPINNER_VISIBLE, payload: true }) //<-- S ...

Incorporated iframe covering the entire browser window

Currently, I find myself in a strange predicament. The scenario involves a JSP+Servlet+Spring MVC application that is integrated within a parent application developed using Angular4 through an iframe. The issue arises when the Spring MVC app redirects to ...

Unable to set intricate information to array variable in Angular 6

I have successfully implemented a method for retrieving data from an HTTP request, and it is functioning well, returning a complex list of data. https://i.sstatic.net/Hxpz2.png However, my concern arises when I try to assign the returned list to a variab ...

The zip() operator in RxJS is not functioning as intended. It consistently finishes execution without emitting any values

Suppose you have an observable containing a large number of elements, say 450 or more. You want to transfer these elements to a different observable in batches of 100 elements each. You can check out a functional example provided by @martin at this link: ...

What is the best way to showcase a standalone JSON object within the template?

I have a detailed component that is designed to show the 5-day forecast for a specific city. I have successfully retrieved the data using the http.get(Url) method. However, I am unsure of how to bind this JSON data to my view. I am familiar with displayi ...

Challenges of implementing dark mode with a checkbox and local storage

I'm experiencing an issue with local storage. When I enable the dark mode, everything functions properly and the local storage 'dark' is set to true. However, upon refreshing the page, the local storage remains true but the toggle switches b ...