1

I am using NodeJS to generate my PreSigned URL using digital ocean API (AWS SDK S3) and passing it to my frontend Angular App, which is making a PUT request to upload a file. There starts the problem it is throwing a CORS error as shown below from my browsers (Chrome and Firefox).

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at [https‍://dflowbucket.sfo3.digitaloceanspaces.com/images-1690112583187-pdf-test.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=DO00B48K2AUXRE8KXVWN%2F20230723%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20230723T114303Z&X-Amz-Expires=900&X-Amz-Signature=66076aaa6dfe6b11eb9d29a37e124a97b0d0aa36baab97207d0edb697218ec58&X-Amz-SignedHeaders=host&x-amz-acl=public-read&x-id=PutObject](https‍://dflowbucket.sfo3.digitaloceanspaces.com/images-1690112583187-pdf-test.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=DO00B48K2AUXRE8KXVWN%2F20230723%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20230723T114303Z&X-Amz-Expires=900&X-Amz-Signature=66076aaa6dfe6b11eb9d29a37e124a97b0d0aa36baab97207d0edb697218ec58&X-Amz-SignedHeaders=host&x-amz-acl=public-read&x-id=PutObject (*Reason: CORS header ‘Access-Control-Allow-Origin’ missing*). Status code: 400.

When I try PUT from postman file is turning into private even though my ACL is 'public-read'

NodeJS Code

exports.getPreSignedUrl = async (fileName, contentType) => {

    const params = {
      Bucket: digitalocean.BUCKET_NAME,
      Key: fileName,
      ContentType: contentType,
      ACL: 'public-read'
    };
  
    return await getSignedUrl(s3Client, new PutObjectCommand(params), { expiresIn: 15 * 60 });
}
}

router.post("/getPreSignedUrl", async (req, res) => {
    const {fileName, contentType} = req.body
    const signedUrl = await digitalocean.getPreSignedUrl(fileName,contentType)
    res.status(200).send({ signedUrl });
});

Angular Code

  onSave() {
    if (this.isLoading) { return }
    if (!this.files.length) {
      this._snackBar.open("You need to choose file first!", 'Close', {
        duration: 2000,
      });
      return;
    }
    const file = this.files[0];
    const contentType = file.type;
    const fileName = 'images-' + `${new Date().getTime()}-${file.name.toLowerCase()}`
    this.isLoading = true;
    this.itemService
      .getPreSignedUrl({ fileName, contentType : '*' })
      .subscribe((res: { signedUrl: string }) => {
        const signedUrl = res.signedUrl
        this.http.put(signedUrl, file) // My PUT request for pre-signed URL
          .subscribe((output) => {
            this.itemService
              .saveTechLink({ fileName }, this.data.itemId)
              .pipe(take(1))
              .subscribe((res: { sharedLink: string }) => {
                this.isLoading = false;
                this.dialogRef.close(res.sharedLink)
              })
          },
            (error) => {
              console.error('Error uploading file:', error);
            }
          );
      })
  }

I have tried many solutions suggested in the internet, but nothing seems to be working

Advanced CORS Options

     Origin : * 
     Allowed Methods : GET, PUT
     Allowed Headers : *
     Access Control Max Age: 300

I have added cors.xml file

<?xml version="1.0" encoding="UTF-8"?>
 <CORSConfiguration>
  <CORSRule>
     <AllowedOrigin>*</AllowedOrigin>
     <AllowedMethod>GET</AllowedMethod>
     <AllowedMethod>HEAD</AllowedMethod>
     <AllowedMethod>PUT</AllowedMethod>
     <AllowedMethod>POST</AllowedMethod>
     <MaxAgeSeconds>3000</MaxAgeSeconds>
     <AllowedHeader>*</AllowedHeader>
   </CORSRule>
  </CORSConfiguration>

it doesn't matter what I try, every time I am getting the same error as shown below

enter image description here

1 Answers1

0

It seems like it is the issue with Angular http request, not with digital Ocean. I tested this with fetch and it started working. I know it is not the correct way, but httpClient blocking the same request for some reason. below is my code which is working fine.

  onSave() {
    if (this.isLoading) { return }
    if (!this.files.length) {
      this._snackBar.open("You need to choose file first!", 'Close', {
        duration: 2000,
      });
      return;
    }
    const file = this.files[0];
    const contentType = file.type;
    const fileName = 'images-' + `${new Date().getTime()}-${file.name.toLowerCase()}`
    this.isLoading = true;
    this.itemService
      .getPreSignedUrl({fileName,contentType})
      .subscribe((res: { signedUrl: string }) => {
        const signedUrl = res.signedUrl
        const headers = new Headers({'Content-Type': contentType, 'x-amz-acl':'public-read'});
        const putConfig = { method: 'PUT', body: file, headers: headers }
        fetch(signedUrl, putConfig ) // This is working
        .then(output => {
            this.itemService
              .saveTechLink({ fileName }, this.data.itemId)
              .pipe(take(1))
              .subscribe((res: { sharedLink: string }) => {
                this.isLoading = false;
                this.dialogRef.close(res.sharedLink)
              })
        }).catch(error => console.error('Error uploading file:', error))
      })
  }