Статьи

Простой URL-анализ с изоморфным JavaScript

Большинство веб-приложений требуют парсинга URL, будь то для извлечения имени домена, реализации REST API или поиска пути к изображению. Типичная структура URL описана изображением ниже:

Структура URL

Вы можете разбить строку URL на составные части, используя регулярные выражения, но это сложно и не нужно …

Разбор URL на стороне сервера

Node.js (и вилки, такие как io.js) предоставляют API URL :

// Server-side JavaScript var urlapi = require('url'), url = urlapi.parse('http://site.com:81/path/page?a=1&b=2#hash'); console.log( url.href + '\n' + // the full URL url.protocol + '\n' + // http: url.hostname + '\n' + // site.com url.port + '\n' + // 81 url.pathname + '\n' + // /path/page url.search + '\n' + // ?a=1&b=2 url.hash // #hash ); 

Как видно из приведенного выше фрагмента, метод parse() возвращает объект, содержащий необходимые данные, такие как протокол, имя хоста, порт и т. Д.

Разбор URL на стороне клиента

В браузере нет эквивалентного API. Но если есть что-то, что браузеры делают хорошо, это разбор URL, и все ссылки в DOM реализуют подобный интерфейс Location , например:

 // Client-side JavaScript // find the first link in the DOM var url = document.getElementsByTagName('a')[0]; console.log( url.href + '\n' + // the full URL url.protocol + '\n' + // http: url.hostname + '\n' + // site.com url.port + '\n' + // 81 url.pathname + '\n' + // /path/page url.search + '\n' + // ?a=1&b=2 url.hash // #hash ); 

Если у нас есть строка URL, мы можем использовать ее в элементе привязки в памяти ( a ), чтобы ее можно было проанализировать без регулярных выражений, например:

 // Client-side JavaScript // create dummy link var url = document.createElement('a'); url.href = 'http://site.com:81/path/page?a=1&b=2#hash'; console.log(url.hostname); // site.com 

Изоморфный разбор URL

Аурелио недавно обсуждал изоморфные приложения JavaScript . По сути, это прогрессивное усовершенствование, доведенное до экстремального уровня, когда приложение будет успешно работать на клиенте или сервере. Пользователь с современным браузером будет использовать одностраничное приложение. Старые браузеры и роботы поисковых систем увидят альтернативу, предоставляемую сервером. Теоретически, приложение может реализовывать различные уровни обработки клиент-сервер в зависимости от скорости и пропускной способности устройства.

Изоморфный JavaScript обсуждался много лет, но он сложен. Несколько проектов идут дальше, чем
реализация разделяемых представлений, и не так много ситуаций, когда стандартное прогрессивное улучшение не сработало бы так же хорошо (если не лучше, учитывая, что большинство «изоморфных» фреймворков не работают без JavaScript-кода на стороне клиента) . Тем не менее, можно создать независимые от среды микробиблиотеки, которые предлагают предварительный первый шаг в изоморфных концепциях.

Давайте рассмотрим, как можно написать библиотеку для разбора URL-адресов в файле lib.js Сначала мы определим, где работает код:

 // running on Node.js? var isNode = (typeof module === 'object' && module.exports); 

Это не особенно module.exports так как вы могли бы иметь функцию module.exports определенную на стороне клиента, но я не знаю лучшего способа (предложения приветствуются) . Аналогичный подход, используемый другими разработчиками, заключается в проверке наличия объекта window :

 // running on Node.js? var isNode = typeof window === 'undefined'; 

Давайте теперь дополним наш код URLparse функцией URLparse :

 // lib.js library functions // running on Node.js? var isNode = (typeof module === 'object' && module.exports); (function(lib) { "use strict"; // require Node URL API var url = (isNode ? require('url') : null); // parse URL lib.URLparse = function(str) { if (isNode) { return url.parse(str); } else { url = document.createElement('a'); url.href = str; return url; } } })(isNode ? module.exports : this.lib = {}); 

В этом коде я использовал переменную isNode для ясности. Однако этого можно избежать, поместив тест непосредственно в последнюю скобку фрагмента.

На стороне сервера URLparse экспортируется как модуль Common.JS. Чтобы использовать это:

 // include lib.js module var lib = require('./lib.js'); var url = lib.URLparse('http://site.com:81/path/page?a=1&b=2#hash'); console.log( url.href + '\n' + // the full URL url.protocol + '\n' + // http: url.hostname + '\n' + // site.com url.port + '\n' + // 81 url.pathname + '\n' + // /path/page url.search + '\n' + // ?a=1&b=2 url.hash // #hash ); 

На стороне клиента URLparse добавляется как метод к глобальному объекту lib :

 <script src="./lib.js"></script> <script> var url = lib.URLparse('http://site.com:81/path/page?a=1&b=2#hash'); console.log( url.href + '\n' + // the full URL url.protocol + '\n' + // http: url.hostname + '\n' + // site.com url.port + '\n' + // 81 url.pathname + '\n' + // /path/page url.search + '\n' + // ?a=1&b=2 url.hash // #hash ); </script> 

За исключением метода включения библиотеки, API клиента и сервера идентичны.

Следует признать, что это простой пример, и URLparse выполняет (в основном) отдельный код на клиенте и сервере. Но мы реализовали непротиворечивый API, и он показывает, как можно написать код JavaScript для запуска в любом месте. Мы могли бы расширить библиотеку, чтобы предлагать дополнительные функции клиент / сервер, такие как проверка полей, анализ файлов cookie, обработка дат, форматирование валюты и т. Д.

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