Changing URL Address Without Redirecting in Modern Web Applications: From Hash Fragments to History API

Dec 02, 2025 · Programming · 11 views · 7.8

Keywords: Non-redirecting URL Changes | Hash Fragment Technique | History API

Abstract: This article provides an in-depth exploration of techniques for changing URL addresses without page redirection in single-page applications (SPAs). It begins by examining the traditional hash fragment approach, detailing how to modify the portion of the URL following the # symbol to alter the browser address bar display without triggering page refresh. The article analyzes the working principles, browser history management mechanisms, and practical application scenarios of this method. Subsequently, it focuses on the pushState() method of the HTML5 History API, comparing the advantages and disadvantages of both technologies, including cross-browser compatibility, SEO friendliness, and user experience differences. Through specific code examples and real-world case studies, this paper offers comprehensive technical selection guidance for developers.

Technical Background of Non-Redirecting URL Changes

In modern web application development, particularly within the architecture of Single Page Applications (SPAs), developers frequently need to update the URL in the browser address bar without triggering a full page refresh. This requirement stems from the pursuit of smoother user experiences and the need to maintain synchronization between application state and URLs. Traditionally, directly assigning values to window.location causes page redirection, which undermines the core advantages of SPAs.

Hash Fragment Technique: The Traditional Solution

Before the advent of the HTML5 History API, the most common technique for non-redirecting URL changes was through modifying the hash fragment portion of the URL. The hash fragment is the content following the # symbol in a URL, originally designed for anchor navigation within documents.

A JavaScript code example for modifying hash fragments:

// Set new hash value
document.location.hash = "article-1";

// Actual URL becomes: http://example.com/#article-1
// Page does not reload

The core advantage of the hash fragment technique lies in its extensive browser compatibility, with nearly all modern browsers supporting this feature. When the hash value changes, the browser automatically adds the new URL to the history, allowing users to navigate using the browser's forward and back buttons.

Event Listening for Hash Changes

To respond to hash changes and execute corresponding application logic, developers need to listen for the hashchange event:

window.addEventListener('hashchange', function() {
    var currentHash = window.location.hash;
    
    // Remove the leading # symbol
    var hashValue = currentHash.substring(1);
    
    // Execute application logic based on hash value
    if (hashValue === "article-1") {
        loadArticle(1);
    } else if (hashValue === "gallery") {
        showGallery();
    }
});

In practical applications, hash values can store more complex data structures. Through JSON serialization, developers can store complete application states in the hash:

// Store complex state
var appState = {
    view: 'article',
    id: 123,
    page: 5,
    filters: ['recent', 'popular']
};

document.location.hash = 'state=' + encodeURIComponent(JSON.stringify(appState));

// Parse state
window.addEventListener('hashchange', function() {
    var hash = window.location.hash.substring(1);
    if (hash.startsWith('state=')) {
        var stateStr = hash.substring(6);
        var state = JSON.parse(decodeURIComponent(stateStr));
        restoreApplicationState(state);
    }
});

HTML5 History API: The Modern Solution

With the widespread adoption of HTML5, the History API provides more powerful URL management capabilities. The history.pushState() method allows developers to directly modify the path portion of the URL, not just the hash fragment.

Basic usage example:

// Modify URL path without redirecting page
history.pushState(
    { articleId: 1, pageTitle: 'Article Title' }, // State object
    '', // Title (ignored by most browsers)
    '/articles/1' // New URL path
);

The three parameters of the pushState() method are: state object (for storing data related to the current history entry), page title (typically an empty string), and new URL. After calling this method, the browser address bar displays the new URL but does not make a request to the server.

Event Handling with History API

When users navigate via browser buttons (forward/back) or programmatically call history.back() or history.forward(), the popstate event is triggered:

window.addEventListener('popstate', function(event) {
    // event.state contains the state object passed during pushState()
    var state = event.state;
    
    if (state && state.articleId) {
        // Restore application view based on state
        loadArticle(state.articleId);
    }
});

Technical Comparison and Selection Recommendations

Hash fragment technique and History API each have advantages and disadvantages, suitable for different application scenarios:

Advantages of Hash Fragment Technique:

Limitations of Hash Fragment Technique:

Advantages of History API:

Limitations of History API:

Best Practices in Practical Applications

In actual projects, a progressive enhancement strategy is recommended:

// Check if browser supports History API
if (window.history && window.history.pushState) {
    // Use History API
    function navigateTo(url, state) {
        history.pushState(state, '', url);
        updateContentBasedOnState(state);
    }
    
    // Listen for popstate events
    window.addEventListener('popstate', handlePopState);
} else {
    // Fallback to hash fragment technique
    function navigateTo(url, state) {
        // Store state in hash
        var hash = 'state=' + encodeURIComponent(JSON.stringify(state));
        window.location.hash = hash;
    }
    
    // Listen for hashchange events
    window.addEventListener('hashchange', handleHashChange);
}

For server-side configuration, ensure all client routes return the same HTML file (typically index.html), then let frontend JavaScript determine what to display based on the URL. In Apache servers, configure via .htaccess file:

RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

Security Considerations and Precautions

When using these techniques, consider the following security aspects:

  1. State Object Size Limits: The state object in pushState() has size limitations (typically 640k characters), avoid storing excessively large objects.
  2. Sensitive Information: Avoid storing sensitive information in URLs or state objects, as they may be visible to users or shared.
  3. Cross-Origin Restrictions: pushState() can only modify same-origin URLs, not for cross-origin navigation.
  4. Server-Side Validation: Even with client-side routing, important data validation and permission checks must still be performed server-side.

Future Development Trends

As web technologies continue to evolve, URL management techniques are also progressing. The Navigation API, as a modern alternative to the History API, is undergoing standardization, offering more powerful and consistent routing management capabilities. Meanwhile, modern frontend frameworks (such as React Router, Vue Router, etc.) have built-in encapsulation of these technologies, allowing developers to focus more on business logic rather than low-level implementation details.

Regardless of the chosen technology, the core objective remains providing smooth user experiences while maintaining synchronization between application state and URLs. Through appropriate technical selection and implementation, developers can create modern web applications that are both aesthetically pleasing and functionally powerful.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.