Mastering Cross‑Browser Image Uploads with XHR, FormData, and CORS

This tutorial explains how to build a robust front‑end image‑upload component for identity verification that works across modern and legacy browsers, leverages Ajax/XHR with FormData, shows progress handling, solves cross‑origin issues with CORS, and provides a Flash fallback for older IE versions.

JD.com Experience Design Center
JD.com Experience Design Center
JD.com Experience Design Center
Mastering Cross‑Browser Image Uploads with XHR, FormData, and CORS

Introduction

Because identity verification is sensitive, many e‑commerce sites require users to upload ID photos. This article walks through building a front‑end image‑upload component that works across browsers, supports OCR verification, and handles cross‑origin requests.

JD Unified Identity Component

Jingdong provides a whole‑site component that manages real‑name authentication, compatible with IE7+ and supports cross‑domain integration.

Component UI screenshot
Component UI screenshot

Implementation with Ajax and XHR

The upload uses Ajax (XMLHttpRequest). Basic XHR Level 1 limitations and Level 2 improvements are listed.

Only supports text data, no binary file upload.

No progress information, only completion status.

Subject to Same‑Origin Policy.

Can set request timeout.

Can use FormData to manage form data.

Can upload files.

Supports cross‑origin requests.

Can receive binary data from server.

Provides upload progress information.

FormData was introduced in XHR Level 2, but has compatibility concerns (see chart).

FormData compatibility chart
FormData compatibility chart

Progress Bar

Use the upload property of XHR (XMLHttpRequestUpload) to monitor progress.

var param = new FormData();
param.append('imgData', file);
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', _self.uploadProgress, false);
xhr.upload.addEventListener('load', _self.uploadComplete, false);
xhr.upload.addEventListener('error', _self.uploadFailed, false);
xhr.upload.addEventListener('abort', _self.uploadCanceled, false);
xhr.open('POST', url);
xhr.send(param);

Cross‑Domain Solutions

Two approaches are considered: JSONP (cannot use POST, therefore discarded) and CORS (supported in XHR Level 2). CORS requires server configuration of Access-Control-Allow-Origin and cannot use a wildcard when withCredentials is true.

CORS compatibility chart
CORS compatibility chart

Support for Older Browsers

IE10‑ and lower cannot use FormData or CORS. The fallback uses Flash via SWFUpload. Configuration example is shown.

var setting = {
  debug: false,
  upload_url: url,
  flash_url: 'flashurl/swfupload.swf?' + Math.random(),
  file_post_name: 'imgData',
  post_params: { sessionId: opts.param.sessionId },
  file_types: '*.bmp;*.jpeg;*.jpg;*.gif;*.png',
  file_size_limit: opts.fileSizeLimit,
  // other settings …
};
var swfupload = new SWFUpload(setting);

Login Verification (Cookies)

XHR does not send cookies on CORS requests unless withCredentials = true and the server allows the specific origin. Flash also needs manual cookie handling.

var param = new FormData();
param.append('imgData', file);
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', _self.uploadProgress, false);
xhr.open('POST', url);
xhr.withCredentials = true;
xhr.send(param);
Note: When withCredentials is set, Access-Control-Allow-Origin cannot be "*"; it must be a concrete domain.

Preflight OPTIONS Request

Because the upload is a “complex request”, the browser first sends an OPTIONS request without cookies. The server must respond to OPTIONS to avoid being blocked.

Preflight request diagram
Preflight request diagram

Component API

The component exposes configurable options such as container selector, custom styles, default identity type, error callbacks, upload URL, and submit callbacks.

seajs.use(['componentURL'], function (auth) {
  auth.page({
    componentKey: '',
    transactionId: '1',
    container: '.renzheng',
    title: '',
    id: 'authP',
    showMsgFn: function (msg) { alert(msg); },
    onReady: function (el) {},
    onSubmit: function (data) {}
  });
  $('.submit-btn').bind('click', function () {
    auth.submit(function (data) {
      console.log(JSON.stringify(data));
    });
  });
});

Conclusion

Building this component deepens understanding of cross‑origin techniques, CORS usage, and practical solutions for older browsers. It should help developers implementing image‑upload features.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

frontendCORSimage uploadXHRFormDatacross‑browser
JD.com Experience Design Center
Written by

JD.com Experience Design Center

Professional, creative, passionate about design. The JD.com User Experience Design Department is committed to creating better e-commerce shopping experiences.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.