Что нового
  • Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Пишем Сокращатель Ссылок При Помощи Aws Lambda За 2 Часа

Sascha

Заместитель Администратора
Команда форума
Администратор
Регистрация
9 Май 2015
Сообщения
1,071
Баллы
155
Возраст
51
Рассказывает

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Интересное требование возникло на работе, когда мы обсуждали потенциальную необходимость запуска собственного сокращателя URL, потому что механизм

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

(в iOS 9 и выше) требует JSON-манифест на https://domain.com/apple-app-site-association.

Поскольку ОС не следует переадресациям, этот манифест должен быть размещен в корневом домене URL-сокращателя.

Из-за

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

на AppsFlyer он не может сокращать URL, когда в приложении настроены универсальные ссылки. Мы могли бы перейти на другого поставщика, но это означало бы большую нагрузку для клиентских приложений.

Возник вопрос «Стоит ли создавать свой сокращатель ссылок?», который затем плавно перешел в «Насколько тяжело создать расширяемый сокращатель ссылок в 2017 году?».

Оказалось, что совсем не трудно, так как на то, чтобы внедрить, протестировать и развернуть, у меня ушло менее двух часов.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.


Вот так выглядит сокращатель

Lambda во имя победы


Для нашего сокращателя нам необходимы следующие вещи:

  1. Конечная точка GET/{shortUrl}, которая будет перенаправлять на оригинальный URL.
  2. Конечная точка POST/, которая будет принимать оригинальный URL и возвращать сокращенный.
  3. index.html — страница, где каждый мог бы легко создать короткий URL.
  4. Конечная точка GET/apple-app-site-association, которая обслуживает статичный JSON-ответ.

Все эти вещи могут быть достигнуты с помощью API Gateway и Lambda.

Прим. перев. Чтобы иметь представление о всём спектре сервисов, предоставляемых платформой Amazon Web Services (AWS), советуем прочитать

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

.

У меня получилась следующая структура проекта:

  • используется шаблон aws-nodejs фреймворка

    Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

    ;
  • каждая конечная точка имеет соответствующую функцию обработки;
  • файл index.html в статичной папке;
  • тесты написаны таким образом, что могут использоваться

    Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

    ;
  • скрипт build.sh, облегчающий работу;
  • интеграционные тесты ./build.sh int-test {env} {region} {aws_profile};
  • приемочные тесты ./build.sh acceptance-test {env} {region} {aws_profile};
  • разворачивание ./build.sh deploy {env} {region} {aws_profile}.

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.


Структура проекта

Конечная точка GET/apple-app-site-association


Так как JSON статичный, есть смысл вычислить HTTP-ответ заранее и возвращать его каждый раз:

'use strict';

const payload = {...
};

const response = {
statusCode: 200,
body: JSON.stringify(payload)
};

module.exports.handler = (event, context, callback) => {
callback(null, response);
};

Конечная точка POST/


Для алгоритма сокращения URL можно найти простое и элегантное

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

на StackOverflow. Вам нужен только автоматически увеличивающийся ID, вроде того, что вы обычно получаете с помощью RDBMS.

Однако я заметил, что DynamoDB будет более подходящей базой данных по следующим причинам:

  • это управляемый сервис, поэтому не надо волноваться об инфраструктуре;

  • Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

    расходы лучше

    Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

    ;
  • есть возможность масштабировать пропускную способность чтения и записи, чтобы соответствовать уровню использования и обрабатывать любые скачки трафика.

Но в DynamoDB нет такого понятия, как автоматически увеличивающийся ID, который необходим для алгоритма. Вместо него вы можете использовать

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

для симуляции автоматического увеличения за счет дополнительной единицы записи за запрос.

function* getNewId () {
console.log('fetching the next auto-incremented ID');

let params = {
TableName: 'url_shortener_long_urls',
Key: {
shortUrl: "__id"
},
UpdateExpression: 'add #counter :n',
ExpressionAttributeNames: {
'#counter': 'counter'
},
ExpressionAttributeValues: {
':n': 1
},
ReturnValues: 'UPDATE_NEW'
};

let res = yield dynamodb.updateAsync(params);
console.log(res);
return res.Attributes.counter;
}


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.


Получится такая таблица

Конечная точка GET/{shortUrl}


Как только мы установили соответствие в таблице DynamoDB, конечная точка перенаправления стала простым взятием оригинального URL и возвращением его как части заголовка Location.

И не забудьте возвращать соответствующий статус коду HTTP, в данном случае 308 (обязательное перенаправление).

module.exports.handler = co.wrap(function* (event, context, callback) {
console.log(JSON.stringify(event));

try {
let shortUrl = event.pathParameters.shortUrl;
console.log('short url : ${shortUrl}');

let longUrl = yield getLongUrl(shortUrl);
console.log('long url : ${longUrl}');

const response = {
statusCode: 308,
headers: { location: longUrl }
};

callback(null, response);
} catch (err) {
console.log(err);

if (err.statusCode) {
callback(null, err);
} else {
callback(null, {
statusCode: 500,
body: JSON.stringify(err)
});
}
}
});

Страница GET/index


Наконец, для страницы index мы будем возвращать HTML (и другой тип контента вместе с HTML).

Я решил поместить HTML-файл в статичную папку, которая загружается и кэшируется в первый раз, когда вызывается функция.

const co = require('co');
const Promise = require('bluebird');
const fs = Promise.promisifyAll(require("fs"));

var html;

function* loadHtml () {
if (!html) {
console.log('loading index.html...');
html = fs.readFileAsync('static/index.html', 'utf-8');
console.log('loaded');
}

return htnl;
}

module.exports.handler = co.wrap(function* (event, context, callback) {
let html = yield loadHtml();
let response = {
statusCode: 200,
headers: {
'Content-Type': 'text/html; charset=UTF-8'
},
body: html
};

callback(null, response);
});

Подготовка к работе


К счастью, у меня было много опыта

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

, поэтому я знаю, что для URL-сокращателя нам необходимо:

  • настроить автомасштабируемые параметры для таблицы DynamoDB (для которой у нас есть внутренняя система управления автоматическим масштабированием);
  • включить кэширование для API Gateway на производственном уровне.
Будущие улучшения


Если поместить один и тот же URL несколько раз, то вы будете получать разные короткие ссылки. Для оптимизации нужно возвращать одну и ту же ссылку, используя кэш.

Чтобы это сделать, вы можете:

  1. Добавить GSI в таблице DynamoDB к longUrl для поддержки эффективного обратного поиска.
  2. В функции shortUrl выполнять GET вместе с GSI для поиска существующих коротких URL.

Более подходящим вариантом будет добавление GSI, нежели создание новой таблицы. Это поможет избежать транзакций между несколькими таблицами.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

.
 
Вверх