- PVSM.RU - https://www.pvsm.ru -
Привет.
Сегодня я попытаюсь рассказать тебе о написании простого сервиса для сокращения ссылок на ASP.Net/DBLinq
Пару дней назад прочитал пост о Антивирусе Бабушкина и у меня повилось желание что-нибудь СЖАТЬ, но в творческое русло я смог направить его только сегодня.
Мне захотелось сделать небольшой сервис по сокращению ссылок, а движок написать самому.
Почему же я решил изобрести велосипед, а не воспользоваться готовым продуктом?
Во-первых, все существующие решения написаны на PHP, a PHP-не язык я не люблю.
Во-вторых, движки занимали мегабайты даже в zip-архивах, что слишком много для программы, которая лишь добавляет записи в бд и отдает по ключу.
Наконец, разминка для мозгов никогда не помешает.
У меня был стандартый LAMP сервер, закрытый nginx-фронтэндом и Cloudflare [1].
В качестве Linq-to-SQL провайдера воспользовался DBLinq [2].
За рерайт URL отвечает простейший .htaccess
Нужны были всего три функции: добавление URL, отдача человеку и роботу и логгирование.
Для них хватило этих таблиц:
В таблице main хранятся
в log:
В urls хранятся дедуплицированные цели ссылок и referrer'ы.
Ради упрощения кода и уменьшения размера бд не реализована поддержка IPv6 в логах/информации о добавившем.
Итоговое приложение состоит из трех основных страниц:
Несмотря на кажущийся объем кода, основная суть сервиса сводится к нескольким строкам, которые приведены ниже в упрощенном виде.
Добавление (упрощено для удобства чтения, в сорцах по-другому):
//Ищем id добавляемой ссылки в бд, если нет - добавляем
var query = _SQLConnection.URLS.Where(a => a.URL == __NewUrlString);
if (query.Any())
__NewUrl=query.First()
else
{
SQLConnection.URLS.InsertOnSubmit(__NewUrl = new URLS() { URL = __NewUrlString });
}
_SQLConnection.Main.InsertOnSubmit(
__NewRecord = new Main() {
AddedIP = BitConverter.ToInt32(IPAddress.Parse(Request.UserHostAddress).GetAddressBytes(),0),
//Сохраняем адрес добавившего
Date = DateTime.Now,
//дату добавления
URL = __NewUrl.ID
//и id ссылки
});
Отдача:
var URLz = _SQLConnection.Main.Where(a => a.ID == urlID).Join(_SQLConnection.URLS,a => a.URL,a => a.ID,( a, b ) => b).Take(1).ToArray();
//пытаемся загрузить ссылки с подходящим ключём.
if ( URLz.Length == 0 ) {
//Не нашли? Выходим!
_e(404);
return;
}
//redirect
Response.Redirect(Server.HtmlDecode(URLz[0].URL), false);
Проблема коротких ключей для ссылок была решена достаточно просто: id записи приводится к строке в 64-тичной системе счисления([a-zA-Z0-9!@]+)
static char[] chars = "!0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray();
public static string ToStr(int input) {
StringBuilder s = new StringBuilder(20);
do {
s.Append(chars[input % 64]);//never use bitwise opertions on server!
input /= 64;
}
while ( input > 0 );
return s.ToString();
}
Для генерации xml с ответом для роботов я не стал заморачиваться с нормальной генерацией xml и запилил простейший, но быстрый костыль.
void xw( string msg, string status ) {
Response.Write(
String.Format(
"<?xml version="1.0" encoding="utf-8"?>rn<response>rnt<status>{0}</status>rnt<message>{0}</message>rn</response>",
status,
msg
)
);
}
Естесственно сервис коротких ссылок никому не нужен, если его ссылки длиннее, чем исходные.
Для исправления этого необходимо написать несколько правил рерайтов для Apache.
Делаем короткий URL для запросов на редирект — теперь ссылка будет выглядеть как who.ec/iXXX
RewriteCond %{REQUEST_URI} ^/?i.*
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule /?i(.*) /get.aspx?url=$1 [L]
Аналогично для добавления — ссылки вида who.ec/add_robot.aspx?url=XXX превратились
в who.ec/pXXX
RewriteCond %{REQUEST_URI} ^/?p.*
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule /?p(.*) /add_robot.aspx?url=$1 [L]
Наконец, закроем несуществующие страницы заглушкой
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !^.*add.aspx
RewriteRule (.*) /add.aspx [L]
Так как скрипт с самого начала был выложен в паблик, то я просто не могу не дать информации по использованию.
Все просто:
Все настройки хранятся в web.config — это позволяет обращаться к ним из кода по ConfigurationManager.AppSettings[<ключ>]
Как написано выше, код рассчитан не только на работу с людьми.
Получение
Добавление
Исходники были выложены [4] на Github.
Пример сокращалки на этом движке можно посмотреть на who.ec [5].
Дизайн для демонстрационного сайта был сделан моим другом stam'ом [6] на Twitter Bootstrap/jQuery/Fancybox.
Автор: kasthack
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/net/28397
Ссылки в тексте:
[1] Cloudflare: http://cloudflare.com
[2] DBLinq: http://code.google.com/p/dblinq2007/
[3] Скачайте: https://github.com/kasthack/whoec_shortener/archive/master.zip
[4] были выложены: https://github.com/kasthack/whoec_shortener
[5] who.ec: http://who.ec
[6] stam'ом: http://stam.epicm.org/
[7] Источник: http://habrahabr.ru/post/171215/
Нажмите здесь для печати.