4

I'm a mac user and never use IE. But yesterday at work I went onto stack overflow and typed this into the browser using IE 9...

http://stackoverflow.com/questions/824349

And they replaced the URL to this without refreshing the page...

http://stackoverflow.com/questions/824349/modify-the-url-without-reloading-the-page

I could not believe what I saw. Any ideas how stack overflow is able to utilize a functionality that mimics the history API's replace state on a browser that does not support it?

gmustudent
  • 2,229
  • 6
  • 31
  • 43

3 Answers3

9

They actually redirect the user with a 301 redirection. Look at the headers:

GET /questions/824349 HTTP/1.1
Host: stackoverflow.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
[...]

HTTP/1.1 301 Moved Permanently
Cache-Control: public, max-age=60
Content-Type: text/html
Expires: Sat, 08 Jun 2013 19:00:05 GMT
Last-Modified: Sat, 08 Jun 2013 18:59:05 GMT
Location: /questions/824349/modify-the-url-without-reloading-the-page
Vary: *
X-Frame-Options: SAMEORIGIN
Date: Sat, 08 Jun 2013 18:59:05 GMT
Content-Length: 0
Marcelo Pascual
  • 810
  • 8
  • 20
3

It's a 301 Moved Permanently redirect, i.e. it's done server side. You don't see a refresh because the browser doesn't open the first URL, it redirects right away to the second.

Here's the result on chrome's console.

enter image description here

Telmo Marques
  • 5,066
  • 1
  • 24
  • 34
2

How to implement a 301 redirect in the same way SO does it.

(Assumes there's a table called questions with columns id and title)

(Note: there's likely also heavy use of Memcached by SO rather than DB access for every page view, but that's another topic.)

For the URL:

http://stackoverflow.com/questions/824349

Your .htaccess will rewrite URLs in the format questions.php?id=123&sef=abc-def:

RewriteRule ^/questions/([0-9]+)/?([\w\-]*)$ /question.php?id=$1&sef=$2

Your question.php script

<?php
// Get the posted id (as int to prevent sql injection)
$id = isset($_GET['id']) ? (int) $_GET['id'] : 0;

// Get the posted search-engine-friendly title string (if any)
$sef = isset($_GET['id']) ? $_GET['sef'] : '';

// Connect to the database
mysqli_connect(...);

// Get the question with the provided id
$result = mysqli_query("SELECT * FROM questions WHERE id = {$id}");

// If a question was found
if ($row = mysqli_fetch_assoc($result)) {
    // Find the SEF title for the question (lowercase, replacing 
    // non-word characters with hyphens)
    $sef_title = strtolower(preg_replace('/[^\w]+/', '-', $row['title']);

    // If the generated SEF title is different than the provided one,
    if ($sef_title !== $sef) {
        // 301 the user to the proper SEF URL
        header("HTTP/1.1 301 Moved Permanently");
        header("Location: http://stackoverflow.com/question/{$id}/{$sef_title}");
    }
} else {
    // If no question found, 302 the user to your 404 page
    header("Location: http://stackoverflow.com/404.php");
}
PeeHaa
  • 71,436
  • 58
  • 190
  • 262
Steven Moseley
  • 15,871
  • 4
  • 39
  • 50