Cloudflare Pages + Alibaba Cloud OSS Uploader: From Failure to a Stable Workflow

A practical recap of a password-protected, dual-site uploader with multipart uploads for large files.

Goal

The project is deployed on Cloudflare Pages. The browser communicates only with same-origin Worker APIs. Long-lived OSS AccessKeys stay in Cloudflare Secrets and are never exposed to the browser.

Core capabilities:

  • Password login and signed session cookies

  • Domestic and overseas upload targets (Hong Kong, Macao, and Taiwan use the overseas target)

  • OSS multipart upload, pause, and resume

  • Remote file listing and one-click link copying

  • A Chinese-first black-and-yellow interface

Final architecture

Browser
│ Same-origin API + session cookie
Cloudflare Pages Advanced Mode / Worker
│ OSS signing inside the Worker
Alibaba Cloud OSS (domestic bucket / overseas bucket)

The essential boundary is simple: browsers never receive long-lived OSS credentials. Only the Worker can read OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET from Cloudflare Secrets.

Key incidents and lessons

1. Generic errors hide the real problem

The initial UI only said that an upload failed because of the network or Worker configuration. That is friendly wording, but poor for diagnosis.

The improvement was to return understandable OSS errors from the Worker and surface the backend detail in the UI, while keeping a concise fallback message. This makes network, authentication, and signing failures distinguishable.

2. SignatureDoesNotMatch is not automatically a credential problem

The error means that the signature calculated by OSS differs from the signature sent in the request.

Check these items in order:

  1. The AccessKey ID and Secret in the Cloudflare Pages Production environment are the same pair.

  2. The bucket region and endpoint match.

  3. The HTTP method, Date, Content-Type, query parameters, and signing string match exactly.

  4. The configuration belongs to the Pages project, not to a separate Cloudflare Worker. These are independent resources and do not share variables automatically.

In this project, listing files worked correctly, proving that credentials, region, and basic signing were valid. The failure was limited to object-path signing during uploads.

3. OSS V1 signing paths and request URL paths must be separate

This was the most important fix.

For file names containing Chinese characters, spaces, or other special characters:

  • The actual URL sent to OSS must be percent-encoded.

  • The OSS V1 CanonicalizedResource must be signed with the original object name.

Signing an already encoded path can leave bucket listing functional, because listing has no object path, while multipart-upload initialization consistently fails with SignatureDoesNotMatch.

The safe approach is to keep the two representations separate:

const rawPath = `/${objectKey}`; // used for V1 signing
const requestPath = encodeOssPath(rawPath); // used only in the fetch URL

This distinction matters for Chinese names, spaces, and special characters.

4. Multipart query parameters must be signed precisely

OSS V1 does not put every URL query parameter into CanonicalizedResource.

  • list-type, prefix, and max-keys belong only in the list request URL.

  • uploads, uploadId, and partNumber are signable OSS subresources for multipart requests.

Including ordinary list parameters in the signature, or omitting multipart subresources, causes signature mismatches.

5. UI updates must preserve the proven core

Replacing an entire HTML file during a theme update can accidentally reintroduce older login or upload code.

A safer workflow is:

  • Keep a proven login, session, and upload script as the baseline.

  • Change only CSS, visible copy, and nonfunctional markup.

  • After publishing, check console errors, login, site switching, file listing, and a real upload.

Pre-release checklist

  • Expected commits are on the GitHub default branch and Cloudflare Pages has deployed them.

  • Production includes SITE_PASSWORD, OSS_ACCESS_KEY_ID, and OSS_ACCESS_KEY_SECRET.

  • Bucket regions, endpoints, and custom domains are correct.

  • Login, listing, and domestic/overseas target switching work.

  • A small file with Chinese characters or spaces has completed a real upload.

  • The library shows the latest 30 files and copied links work.

  • No password or AccessKey Secret appears in code, screenshots, logs, or public documentation.

Reusable principles

  1. Get the real server error before changing code.

  2. For object-storage signing, compare the actual request and the signed data character by character.

  3. Separate visual changes from authentication and upload changes; commit and verify them separately.

  4. A real production upload is required. Local signature tests cannot fully replace it.

  5. Keep credentials in Secrets. Public write-ups should document variable names and principles, never values.

Closing thought

A reliable uploader is more than a polished interface or a single successful API call. Clear system boundaries, actionable errors, exact signing behavior, and real post-deployment verification are what make it maintainable over time.