Текстовые урлы в Эгее

Хочу рассказать о том, как устроены текстовые урлы в Эгее. Эту заметку я публикую, отчасти, для энтузиастов, которые пытаются изменять урлы своих заметок, ковыряясь в базе, чтобы они хотя бы поняли, как эта база устроена, и почему. Ну и просто для тех, кому это может быть любопытно.

Раньше урлы составлялись из дат: у этой заметки был бы урл /2012/08/30/1/, потому что это первая по счёту заметка за 30 августа 2012 года. Проблема таких урлов в полной бессмысленности и незапоминаемости. Более того, из-за того, что в таком урле содержится порядковый номер заметки в дне, чтобы его сгенерировать/разобрать, приходится делать запросы, затрагивающие соседние заметки, и пересчитывать каждую из них с учётом её часового пояса (да, ведь за день может быть написано несколько заметок из разных часовых поясов).

Ещё одна проблема была в том, что если удалить заметку, то урлы написанных после неё в тот же день съедут на единицу вниз. Соответственно, ссылки поломаются. Мало приятного, короче.

Я давно хотел реализовать текстовые урлы, но с ними всё тоже неоднозначно. Во-первых, их надо как-то генерировать. Транслитерировать? А как быть с многоязыковой поддержкой (например, как транслитерировать с иврита)? Или просто давать пользователю ввести самому? Или не обламываться писать по-русски, как делает Википедия? Во-вторых, что делать, если название заметки изменится после публикации? Оставлять старый урл? Менять? Но тогда снова сломаются ссылки. В-третих, что делать со старыми заметками? Оставить со старыми урлами или конвертировать автоматически?

В результате долгих раздумий я решил, что должно быть так:

  1. Урлы должны генериться автоматически, потому что большинству людей нет до них дела, и лишнее поле в форме написания заметки — это лажа.
  2. Любой язык должен уметь транслитерироваться в латиницу (то есть файл языка помимо всяких слов и предложений должен содержать функцию транслитерации).
  3. Пользователь должен иметь возможность поменять урл, если ему сильно надо, и при этом ссылки на старый адрес не должны сломаться. (Это касается только внутренней инфраструктуры; интерфейса для изменения урлов в версии 2.2 пока нет, потому что её нужно было выпустить, и это не входило в список фич для этого релиза. Тем не менее, важно было сразу под капотом всё сделать нормально, чтобы потом было легко добавить это.)
  4. Выходит, мы должны помнить историю урлов каждой заметки, и знать, какой из них «настоящий» (то есть последний). Все старые урлы должны редиректить (301) на новый.
  5. Урлы старых заметок при переходе на новую версию движка меняться не должны, потому что автор этого не увидит, а автоматически изменять что-то в блоге за спиной у автора — это нехорошо. Вдруг там что-то коряво получится. Я не хочу, чтобы моим заметкам прописались какие-то там непонятные урлы без меня.
  6. Каждая заметка должна знать, под каким урлом она была опубликована изначально — это нужно для того, чтобы корректно работали всякие социокнопочки. Им ведь нужен урл заметки, и они ничего не знают о том, что он может поменяться. Если заметку уже залайкали 20 человек под урлом X, то изменение её урла на Y не должно убить эти лайки.

В итоге я реализовал следующую структуру.

В таблице заметок Notes я добавил поле OriginalAlias — это исходный алиас заметки (название для урла), созданный при её публикации. Если это поле пустое, значит заметка была опубликована до Эгеи 2.2, когда алиасов не было, и поэтому её урл должен по старинке составляться из даты и порядкового номера. Поле OriginalAlias вообще никогда не должно меняться после публикации заметки. Соответственно, у «старых» заметок оно навсегда останется пустым (благодаря нему у них не сломаются социолайки, завязанные на урлы из дат, даже если пользователь их поменяет на текстовые).

Для хранения настоящих урлов теперь есть специальная таблица Aliases с полями ID (ключ), EntityID (ключ заметки в таблице Notes), Alias (сам алиас) и Stamp (таймштамп, когда этот алиас был назначен заметке). Для того, чтобы поменять заметке урл, нужно просто дописать в эту таблицу запись с новым алиасом и таймштампом. Урл заметки формируется из алиаса с наибольшим таймштампом, а все старые алиасы редиректят на новые.

Дальше
Мои книги