Osy#betaRun it on Osyrin: osyrin.com

Reference / Config

moved addresses (app.Redirects)

app.Redirects = [ new Redirect("/shop", "/"), new Redirect("/sale", "/c/summer") { Permanent = false } ];

`app.Redirects` lists the addresses your app has moved and where they went. A request for one is answered with a 301, or a 302 for `Permanent = false`, before any page is looked at, so old links, bookmarks and search results keep working. A move that depends on data, such as a product whose slug changed, belongs in the page's own `head { RedirectTo = … }` instead.

stable1 example compiled by CIconfigroutingseo

Summary#

An address that stops working is a broken link everywhere it was ever shared. app.Redirects keeps each old address answering, by sending the visitor, and a search engine, to where the content now lives:

app.Redirects = [
  new Redirect("/shop", "/"),                                // 301 — moved for good
  new Redirect("/sale", "/c/summer") { Permanent = false },  // 302 — for now
];

Signature#

app.Redirects = [ new Redirect(<from>, <to>) { Permanent = <bool> }, … ];

class Redirect {
  string From;              // a path on this app, exactly as it is requested — "/old-name"
  string To;                // a path on this app — "/new-name" — or a full "https://…" address
  bool Permanent = true;    // 301 when true, 302 when false
}

Description#

301 or 302#

A 301 says the move is permanent. A search engine then carries the old address's standing over to the new one and stops listing the old one. A 302 says it is for now, and the old address keeps its standing. Use 302 for a campaign address that points somewhere this month and somewhere else next month.

Answered before any page#

A redirect is checked before any page or [[api-serve|[Serve]]] address is matched. That is why a From that a page or a served body still answers is refused at compile time: the page would be hidden behind the redirect, so the compiler asks you to choose which one you meant. Two entries with one From are refused for the same reason.

A From may be file-shaped (/feed.rss). Every address on the app's host reaches it.

Where it may point#

To is a path on this app, or a full http(s):// address on another site. Moving a feed to a news host is a real case. //host is refused: a browser reads it as another host, even though it looks like a path.

Fixed moves here, data-driven moves on the page#

A move you can write down belongs in this list, such as /shop becoming /. A move that depends on data does not. When a product renames its slug, only the product page knows the old slug maps to the new one, so it says so with head { RedirectTo = … }. That answers the same 301, from the page whose data decides it.

It is computed once per version#

The list is an ordinary expression, so it may be built with a helper or a loop. The platform evaluates it once for each compiled version of the app, not per request. A recompile evaluates it again.

Examples#

An app that moved its shop and its feed#

app.Redirects = [
  new Redirect("/shop", "/"),
  new Redirect("/sale", "/c/summer") { Permanent = false },
  new Redirect("/feed.rss", "https://news.example.com/feed.rss"),
];

[Route("/")]
[AllowAnonymous]
[Title("Home")]
component Home() { render { Text("Welcome"); } }

[Route("/c/summer")]
[AllowAnonymous]
[Title("Summer")]
component Summer() { render { Text("Summer sale"); } }

What the compiler refuses#

app.Redirects = [
  new Redirect("/", "/home"),             // "/" is answered by the page at "/" already
  new Redirect("/old", "//evil.example"), // not an address: a path on this app, or a full https:// address
  new Redirect("/gone", "/a"),
  new Redirect("/gone", "/b"),            // "/gone" is redirected twice
];

See also#

  • head: head { RedirectTo = … }, the move a page's data decides.
  • [Serve]: [Serve("/…")], an address answered with a body instead of a page.
  • routes and pages: how a page gets its address.

Related

head

A routed page's document head — its title, description, canonical address, share image, structured data, whether it may…

[Serve]

Gives a function an address on the app's own origin. A GET at that address answers with the function's return value as…

routes and pages

How a component becomes a page: it declares a route with `[Route("/catalog/{slug}")]`, and navigating to a matching…