Preskoči na sadržaj

Serverless URL redirects using JavaScript on GitHub Pages

As many readers of this blog are already aware, we make great use of GitHub Pages for hosting this website and several others. In particular, after FIDIT's inf2 server was finally decomissioned, Pages was the obvious choice for replacing the remaining services it offered.

Since the number and variety of applications and services hosted on inf2 server grew and diminished organically over time, what remained afterward was a collection of complex, but unrelated link hierarchies that had to be redirected to new locations (remember that Cool URIs don't change).

In particular, redirecting just the index is very simple, e.g. for ELARS Portal accessing https://inf2.uniri.hr/elarsportal/ will redirect to https://fidit-rijeka.github.io/elarsportal/ thanks to the index.html file in the elarsportal directory with the following contents:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="refresh" content="0; url='https://fidit-rijeka.github.io/elarsportal/'" />
  </head>
</html>

This is too tedious to do for every URI, but luckily there are better approaches. We briefly looked into building a "redirect site" using mkdocs-redirects plugin for MkDocs, but ultimately decided even this approach was going to be too much hassle to maintain.

GitHub Pages itself doesn't offer a proper HTTP redirection service, but there is a neat trick using 404 page. After some tinkering coupled together with reading MDN's JavaScript basics, we got to the 404.html file with the following contents:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>inf2 is now retired</title>

    <script>
        window.onload = function () {
            const currentLocation = window.location.href;
            var redirectLocation = 'https://noc.miletic.net/';
            if (currentLocation.startsWith('https://inf2.uniri.hr/elarsportal')) {
                redirectLocation = currentLocation.replace(
                    'https://inf2.uniri.hr/elarsportal',
                    'https://fidit-rijeka.github.io/elarsportal'
                );
            } else if (currentLocation.startsWith('https://inf2.uniri.hr/reStructuredHgWiki')) {
                redirectLocation = currentLocation.replace(
                    'https://inf2.uniri.hr/reStructuredHgWiki',
                    'https://group.miletic.net/hr/nastava'
                );
            } else if (currentLocation.startsWith('https://inf2.uniri.hr/hgwiki') ||
                currentLocation.startsWith('https://inf2.uniri.hr/heterogeneouswiki') ||
                currentLocation.startsWith('https://inf2.uniri.hr/redwiki')) {
                redirectLocation = currentLocation.replace(
                    'https://inf2.uniri.hr/hgwiki',
                    'https://group.miletic.net/hr/nastava/kolegiji'
                ).replace(
                    'https://inf2.uniri.hr/heterogeneouswiki',
                    'https://group.miletic.net/hr/nastava/kolegiji'
                ).replace(
                    'https://inf2.uniri.hr/redwiki',
                    'https://group.miletic.net/hr/nastava/kolegiji'
                );
            } else if (currentLocation.startsWith('https://inf2.uniri.hr/bluewiki')) {
                redirectLocation = 'https://www.inf.uniri.hr/~amestrovic/';
            } else if (currentLocation.startsWith('https://inf2.uniri.hr/request') ||
                currentLocation.startsWith('https://inf2.uniri.hr/server')) {
                redirectLocation = currentLocation.replace(
                    'https://inf2.uniri.hr',
                    'https://apps.group.miletic.net'
                );
            } else if (currentLocation.startsWith('https://inf2.uniri.hr/metod')) {
                redirectLocation = 'https://moodle.srce.hr/';
            }
            document.body.innerHTML = '<p>Please follow <a href="' + redirectLocation + '">this link</a>.</p>';
            window.location.replace(redirectLocation);
        }
    </script>
</head>

<body>
    <p>Please follow <a href="https://noc.miletic.net/">this link</a>.</p>
</body>

</html>

Let's go briefly over the contents and redirect options:

And that's it! Sure, we can extend it further to also handle renamed pages and moved files by adding nested ifs, but this is working well enough for the most of the URIs that we care about. It is also interesting to note that Google recognizes the redirects, despite the HTTP 404 status code returned by the GitHub.com server and the need to execute JavaScript while crawling to figure out the destination URI.