The Ultimate Guide to Formatting HTTP Request Bodies in Frontend: Understanding JSON, FormData, and x-www-form-urlencoded

In actual frontend development, when interacting with backend APIs, have you ever been confused between <span>application/json</span><span>application/x-www-form-urlencoded</span> and <span>multipart/form-data</span>? This article will provide detailed code examples (using Fetch API and Axios) to thoroughly explain the differences, applicable scenarios, and practical applications of these three common Content-Types, allowing you to navigate the path of request body formatting smoothly.The Ultimate Guide to Formatting HTTP Request Bodies in Frontend: Understanding JSON, FormData, and x-www-form-urlencodedThe Ultimate Guide to Formatting HTTP Request Bodies in Frontend: Understanding JSON, FormData, and x-www-form-urlencoded

1. application/json (Most Common)

Usage Scenario: RESTful API, Complex Data Structure Transmission

1. Fetch API Example

// Example 1: Basic POST request
async function postUserData(user) {
    try {
        const response = await fetch('/api/users', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(user) // Key: needs manual serialization
        });
        if (!response.ok) throw new Error('Request failed');
        return await response.json();
    } catch (error) {
        console.error('Error:', error);
    }
}

// Usage example
const user = {
    name: 'Zhang San',
    age: 25,
    hobbies: ['Basketball', 'Swimming'],
    address: {
        city: 'Beijing',
        street: 'Chaoyang District'
    }
};
postUserData(user).then(data => console.log('User created successfully:', data));

// Example 2: More complete encapsulation (Recommended!!!)
class ApiClient {
    async request(url, method = 'GET', data = null) {
        const config = {
            method,
            headers: {
                'Content-Type': 'application/json',
            },
        };
        if (data) {
            config.body = JSON.stringify(data);
        }
        const response = await fetch(url, config);
        return response.json();
    }
    // Shortcut methods
    get(url) { return this.request(url); }
    post(url, data) { return this.request(url, 'POST', data); }
    put(url, data) { return this.request(url, 'PUT', data); }
    delete(url) { return this.request(url, 'DELETE'); }
}

// Usage
const api = new ApiClient();
api.post('/api/products', { name: 'Mobile Phone', price: 2999 });

2. Axios Example

// Example 1: Basic usage (automatically handles JSON serialization)
async function postUserData(user) {
    try {
        const response = await axios.post('/api/users', user, {
            headers: {
                'Content-Type': 'application/json'
            }
        });
        console.log('Response data:', response.data);
        return response.data;
    } catch (error) {
        console.error('Request error:', error.response?.data || error.message);
    }
}

// Usage example
const user = {
    name: 'Li Si',
    email: '[email protected]',
    profile: {
        avatar: 'path/to/avatar.jpg',
        bio: 'Frontend Developer'
    }
};
postUserData(user);

// Example 2: Create Axios instance (Recommended!!!)
const apiClient = axios.create({
    baseURL: 'https://api.example.com',
    timeout: 10000,
    headers: {
        'Content-Type': 'application/json'
    }
});

// Request interceptor (automatically add token)
apiClient.interceptors.request.use(config => {
    const token = localStorage.getItem('authToken');
    if (token) {
        config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
});

// Response interceptor (unified error handling)
apiClient.interceptors.response.use(
    response => response.data,
    error => {
        console.error('API error:', error.response?.data);
        return Promise.reject(error);
    }
);

// Using the encapsulated instance
apiClient.post('/users', user)
    .then(data => console.log('Success:', data))
    .catch(error => console.error('Failed:', error));

2. application/x-www-form-urlencoded

Usage Scenario: Traditional Form Submission, OAuth Authentication, Simple Key-Value Pairs

1. Fetch API Example

// Manual encoding function
function encodeFormData(data) {
    return Object.keys(data)
        .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
        .join('&amp;');
}

// Example 1: Login form submission
async function login(username, password) {
    const formData = {
        username: username,
        password: password,
        grant_type: 'password'
    };
    try {
        const response = await fetch('/oauth/token', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body: encodeFormData(formData)
        });
        return await response.json();
    } catch (error) {
        console.error('Login failed:', error);
    }
}

// Usage
login('zhangsan', 'mypassword123').then(console.log);

// Example 2: Using URLSearchParams (simpler)
async function submitForm(formData) {
    const params = new URLSearchParams();
    params.append('name', formData.name);
    params.append('email', formData.email);
    params.append('message', formData.message);
    const response = await fetch('/api/contact', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: params
    });
    return response.json();
}

// Shortcut: Directly pass FormData (will automatically set the correct Content-Type)
async function quickSubmit(data) {
    const formData = new FormData();
    Object.keys(data).forEach(key => {
        formData.append(key, data[key]);
    });
    const response = await fetch('/api/submit', {
        method: 'POST',
        body: formData // Note: Do not set Content-Type, the browser will set it automatically
    });
    return response.json();
}

2. Axios Example

// Example 1: Using URLSearchParams
async function login(username, password) {
    const params = new URLSearchParams();
    params.append('username', username);
    params.append('password', password);
    params.append('grant_type', 'password');
    try {
        const response = await axios.post('/oauth/token', params, {
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        });
        return response.data;
    } catch (error) {
        console.error('Authentication failed:', error);
    }
}

// Example 2: Using qs library (handling nested objects)
import qs from 'qs';
async function submitComplexData(data) {
    try {
        const response = await axios.post('/api/complex', qs.stringify(data), {
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        });
        return response.data;
    } catch (error) {
        console.error('Submission failed:', error);
    }
}

// Complex data example
const complexData = {
    user: {
        name: 'Wang Wu',
        profile: { age: 30 }
    },
    tags: ['vue', 'react']
};
// qs.stringify result: user[name]=王五&amp;user[profile][age]=30&amp;tags[]=vue&amp;tags[]=react
submitComplexData(complexData);

// Example 3: Global configuration (recommended)
const formApi = axios.create({
    baseURL: '/api',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    transformRequest: [function (data) {
        // Automatically convert request data to URL encoded format
        return qs.stringify(data);
    }]
});
// Usage: directly pass an object, automatically convert
formApi.post('/submit', { name: 'Zhao Liu', age: 28 });

3. multipart/form-data

Usage Scenario: File Upload, Mixed Data (File + Text)

1. Fetch API Example

// Example 1: Single file upload
async function uploadFile(file) {
    const formData = new FormData();
    formData.append('file', file); // 'file' is the expected field name by the backend
    formData.append('description', 'This is a file description');
    formData.append('category', 'documents');
    try {
        const response = await fetch('/api/upload', {
            method: 'POST',
            body: formData // Note: Do not set Content-Type!
        });
        if (!response.ok) throw new Error('Upload failed');
        return await response.json();
    } catch (error) {
        console.error('Upload error:', error);
    }
}

// Usage example
const fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', async (event) => {
    const file = event.target.files[0];
    if (file) {
        const result = await uploadFile(file);
        console.log('Upload result:', result);
    }
});

// Example 2: Multiple file upload + progress monitoring
async function uploadMultipleFiles(files, onProgress) {
    const formData = new FormData();
    // Add multiple files
    files.forEach((file, index) => {
        formData.append(`files`, file); // Same field name, backend receives an array
    });
    // Add other fields
    formData.append('albumName', 'My Album');
    formData.append('isPublic', 'true');
    try {
        const response = await fetch('/api/upload/multiple', {
            method: 'POST',
            body: formData
        });
        return await response.json();
    } catch (error) {
        console.error('Batch upload failed:', error);
    }
}

// Example 3: Encapsulation with progress monitoring
function uploadWithProgress(url, formData, onProgress) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        // Progress monitoring
        xhr.upload.addEventListener('progress', (event) => {
            if (event.lengthComputable) {
                const percent = (event.loaded / event.total) * 100;
                onProgress?.(percent);
            }
        });
        xhr.addEventListener('load', () => {
            if (xhr.status === 200) {
                resolve(JSON.parse(xhr.responseText));
            } else {
                reject(new Error(`Upload failed: ${xhr.status}`));
            }
        });
        xhr.addEventListener('error', () => reject(new Error('Network error')));
        xhr.open('POST', url);
        xhr.send(formData);
    });
}

2. Axios Example

// Example 1: Basic file upload
async function uploadFile(file) {
    const formData = new FormData();
    formData.append('file', file);
    formData.append('description', 'File description');
    try {
        const response = await axios.post('/api/upload', formData, {
            headers: {
                'Content-Type': 'multipart/form-data'
            }
        });
        return response.data;
    } catch (error) {
        console.error('Upload failed:', error);
    }
}

// Example 2: Multiple file upload + progress bar
async function uploadWithProgress(files, onProgress) {
    const formData = new FormData();
    files.forEach(file => {
        formData.append('files', file);
    });
    try {
        const response = await axios.post('/api/upload', formData, {
            headers: {
                'Content-Type': 'multipart/form-data'
            },
            onUploadProgress: (progressEvent) => {
                if (progressEvent.total) {
                    const percent = Math.round(
                        (progressEvent.loaded * 100) / progressEvent.total
                    );
                    onProgress?.(percent);
                }
            },
            timeout: 30000 // 30 seconds timeout
        });
        return response.data;
    } catch (error) {
        if (axios.isCancel(error)) {
            console.log('Upload canceled');
        } else {
            console.error('Upload error:', error);
        }
        throw error;
    }
}

// Usage example
const files = document.getElementById('fileInput').files;
uploadWithProgress(files, (percent) => {
    console.log(`Upload progress: ${percent}%`);
    // Update progress bar UI
    document.getElementById('progressBar').style.width = percent + '%';
});

// Example 3: Advanced encapsulation - supports canceling uploads
class FileUploader {
    constructor() {
        this.cancelTokenSource = null;
    }
    async upload(file, onProgress) {
        // Cancel previous request
        if (this.cancelTokenSource) {
            this.cancelTokenSource.cancel('New upload request');
        }
        this.cancelTokenSource = axios.CancelToken.source();
        const formData = new FormData();
        formData.append('file', file);
        try {
            const response = await axios.post('/api/upload', formData, {
                headers: { 'Content-Type': 'multipart/form-data' },
                onUploadProgress: onProgress,
                cancelToken: this.cancelTokenSource.token
            });
            return response.data;
        } catch (error) {
            if (!axios.isCancel(error)) {
                throw error;
            }
        }
    }
    cancel() {
        if (this.cancelTokenSource) {
            this.cancelTokenSource.cancel('User canceled upload');
        }
    }
}
// Usage
const uploader = new FileUploader();
uploader.upload(file, (progress) => {
    console.log(`Progress: ${progress}%`);
});
// Cancel upload
// uploader.cancel();

Selection Suggestions

  1. Simple Projects → Use Fetch API (reduce dependencies)
  2. Complex Projects → Use Axios (more complete features)
  3. File Upload → Both can be used, Axios’s progress monitoring is simpler
  4. Need Compatibility with Old BrowsersAxios (better polyfill support)

——————Advanced Version:

// Choose the appropriate method based on project requirements
class ApiService {
    constructor(useAxios = true) {
        this.useAxios = useAxios;
        if (useAxios) {
            this.setupAxios();
        }
    }
    setupAxios() {
        this.api = axios.create({
            baseURL: process.env.API_BASE_URL,
            timeout: 10000,
        });
    }
    async request(method, url, data, contentType = 'json') {
        if (this.useAxios) {
            return this.axiosRequest(method, url, data, contentType);
        } else {
            return this.fetchRequest(method, url, data, contentType);
        }
    }
    // Axios implementation
    async axiosRequest(method, url, data, contentType) {
        const config = { method, url };
        if (contentType === 'form-data') {
            const formData = new FormData();
            Object.keys(data).forEach(key => formData.append(key, data[key]));
            config.data = formData;
            config.headers = { 'Content-Type': 'multipart/form-data' };
        } else {
            config.data = data;
        }
        const response = await this.api.request(config);
        return response.data;
    }
    // Fetch implementation
    async fetchRequest(method, url, data, contentType) {
        const config = { method };
        if (contentType === 'form-data') {
            const formData = new FormData();
            Object.keys(data).forEach(key => formData.append(key, data[key]));
            config.body = formData;
        } else if (contentType === 'json') {
            config.headers = { 'Content-Type': 'application/json' };
            config.body = JSON.stringify(data);
        }
        const response = await fetch(url, config);
        if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
        return response.json();
    }
}
// Usage
const api = new ApiService(true); // true uses Axios, false uses Fetch
// Unified calling method
api.request('POST', '/users', { name: 'Zhang San' }, 'json');
ap.request('POST', '/upload', { file: fileObject }, 'form-data');
  1. Be sure to bookmark this!!!!!!!!

Leave a Comment