Что было бы лучшим дизайном для разрешения поиска хоста / порта - PullRequest
3 голосов
/ 18 марта 2011
static image (e.g. car.png)
<table><tr><td><img src="http://<somehost>:<someport>/images/car.png" /></td></tr></table>

(e.g. lookup by id=123456 and fetched via a servlet from the database)
<table><tr><td><img src="http://<somehost>:<someport>/doc?id=123456"/></td></tr></table>

Мы генерируем фрагменты HTML-кода (как упомянуто выше) и сохраняем их в базе данных, которая используется для динамического восстановления пользовательской страницы.

Проблема в вышеприведенном сценарии заключается в том, что somehost / someport статически связан и хранится в базе данных, чего я хотел бы избежать, так как, если мне придется перейти на другую машину с другим IP, все вышеперечисленные вызовы завершатся неудачно.

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

Ответы [ 7 ]

3 голосов
/ 22 марта 2011

Прежде всего, хранение HTML в базе данных не очень хорошая идея. Но аля.

Что касается конкретной проблемы, вы можете просто определить тег HTML <base>, который сделает все относительные URL в документе относительными к нему.

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
...
<head>
    <c:set var="r" value="${pageContext.request}" />
    <base href="${fn:replace(r.requestURL, r.requestURI, '')}${r.contextPath}/" />
</head>

Таким образом, вы можете просто использовать

<table><tr><td><img src="images/car.png" /></td></tr></table>
<table><tr><td><img src="doc?id=123456"/></td></tr></table>

Без базы вы будете зависеть от пути к контексту.


Если вы действительно хотите их параметризовать, то я бы использовал java.text.MessageFormat. Вы можете использовать {0}, {1}, {2} и т. Д. В качестве заполнителей для первого, второго, третьего и т. Д. Параметров.

<table><tr><td><img src="{0}/images/car.png" /></td></tr></table>
<table><tr><td><img src="{0}/doc?id=123456"/></td></tr></table>

Вы можете получить текущий хост / порт (и контекст!) Из HttpServletRequest следующим образом:

HttpServletRequest r = getItSomehow();
String base = r.getRequestURL().toString().replace(r.getRequestURI(), "") + r.getContextPath();

Вы можете отформатировать HTML из БД следующим образом:

String html = getItSomehow();
String formatted = MessageFormat.format(html, base);

А затем отобразите это в JSP. Вы могли бы даже обернуть это в пользовательскую функцию EL. Более того, некоторые фреймворки MVC, такие как JSF, также имеют теги, которые используют MessageFormat под обложками. Э.Г.

<h:outputFormat value="#{bean.html}" escape="false">
    <f:param value="#{bean.base}" />
</h:outputFormat>
1 голос
/ 18 марта 2011

Почему бы вам не использовать этот способ?Это должно работать

static image (e.g. car.png)
<table><tr><td><img src="images/car.png" /></td></tr></table>

(e.g. lookup by id=123456 and fetched via a servlet from the database)
<table><tr><td><img src="/doc?id=123456"/></td></tr></table>
0 голосов
/ 28 марта 2011

Это решение является практически тем, что прокомментировали все остальные, но это более элегантный способ выполнения замен, и это то, что я использовал в приложении.

Почти все параметры хранятся в вашей базе данных, которые являются динамическими. Например, я мог видеть, что [somehost] меняется, даже когда вы находитесь в режиме разработки по сравнению с рабочим режимом. Для решения этой проблемы я создал класс, который массово заменяет переменные. Я называю этот класс Replacer (код ниже).

Я предлагаю вам сохранить [somehost] и все ваши [...] параметры в вашей базе данных в виде таких параметров, как: [x], [y], [z]. Если вы можете поместить x, yz в перечисление и сохранить их порядковый номер в базе данных, например [1], [2], [3], в вашей базе данных, то вы сэкономите много места на дисках БД.

Позже создайте объект Properties, который статически создает статический заменитель, и запустите заменитель для всех данных, поступающих из вашей базы данных.

public class Replacer {

private final Map<String, Object> replacements = new HashMap<String, Object>();

public Replacer () {

    replacements.put("''", "\"");

}

public void addReplacement (String replaceWhat, Object replaceWith) {

    replacements.put(replaceWhat, replaceWith);

}

public String replace ( Object contentToReplace ) {

    String output = contentToReplace.toString();

    for (String replacement : replacements.keySet() ) {

        output = output.replace(replacement, replacements.get(replacement).toString() );

    }

    return output;

}

public static void main (String[] args) throws Exception {

    testReplaceTwoSingleQuote();

}

public static void testReplaceTwoSingleQuote () throws Exception {

    Replacer rep = new Replacer();

    assert rep.replace( "And Mary said, ''Hello Bob''. ").equals("And Mary said, \"Hello Bob\".");

}

}

0 голосов
/ 27 марта 2011

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

Так что сначала разберите ваш документ при создании, чтобы извлечь все именованные хосты (или, если это просто конкретные хосты, поищите их). Затем используйте эти имена хостов (и порты, если они указаны) в качестве ключа для поиска в базе данных. Преобразование вашего имени хоста в уникальный код. Если вы не нашли запись для этого имени хоста, создайте ее и добавьте. В основном конвертируйте ваше имя хоста в представительный код. Теперь немного об обмане DNS. возьмите свой не сгенерированный код и добавьте его к некоторому DNS, который был настроен так, чтобы он указывал на ваш вышеупомянутый веб-сервер. Для этого вам нужно настроить DNS-символы . Итак, чтобы взять пример. Скажите, если ваш исходный контент выглядит так:

<p>Why is it that all my baking ends up on <a href="http://cakewrecks.blogspot.com/p/faq.html">the internet</a></p>

Вы извлекаете имя хоста cakewrecks.blogspot.com. Найдите его в таблице преобразования и преобразуйте в типичный код, скажем, 11ag3. Затем он добавляется к имени хоста веб-сервера, например 11ag3.content.mycompany.com

Теперь вы берете новое имя хоста и вставляете его обратно в ваш контент.

<p>Why is it that all my baking ends up on <a href="http://11ag3.content.mycompany.com/p/faq.html">the internet</a></p>

Далее вам нужно написать сервлет (или, возможно, какой-то другой динамический код). Для этого нужно перехватить любой входящий HTTP-запрос (все ваши запросы из вашего контента теперь должны попадать в этот сервлет, а не туда, куда они изначально отправлялись). Таким образом, сервлет получает запрос на

http://11ag3.content.mycompany.com/p/faq.html

Извлекает имя хоста 11ag3.content.mycompany.com и из этого уникальный код 11ag3. Теперь он делает обратное тому, что мы делали при создании документа, ищет исходное имя хоста и возвращает его обратно в запрос, тем самым восстанавливая http://cakewrecks.blogspot.com/p/faq.html. Теперь он отвечает на запрос кодом состояния HTTP 300 (вероятно, 307, временное перенаправление) вместе с восстановленным URL.

Большим преимуществом здесь является то, что теперь у вас есть таблица базы данных, которая содержит все ваши имена хостов. Если вы хотите изменить источник контента, вы можете просто обновить соответствующую запись новым именем хоста. Кроме того, вы можете избежать накладных расходов на шаблонирование каждой страницы при каждой ее подаче.

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

0 голосов
/ 23 марта 2011

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

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

Скорее создайте правильный кэш на стороне сервера приложений. Чтобы добиться максимальной производительности при компоновке страницы, сократите обычные текстовые элементы в байтовые массивы (если хотите, взломайте сериализатор XML) и используйте средство записи для каждого потока, чтобы применить «somehost», «someport» и «id».

Это даст вам несколько сотен обращений в секунду, если доступ к базе данных не требуется. Если вам удастся хорошо построить и заполнить кеши (разделить и завоевать), хэшируя свои входные запросы, вы, вероятно, получите более 2000 обращений в секунду, если попадание кешей происходит на обычном сервере.

Оптимизируйте дальше, используя такие кеши, как Varnish.

0 голосов
/ 22 марта 2011

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

Теперь вы можете сделать две вещи:

a) Сохранить HTML-код в БД с заполнителями:

<table><tr><td><img src="http://%1:%2/images/car.png" /></td></tr></table>

и замените заполнители, используя

String.format(strHtmlFromDatabase, strHost, strPort);

. Недостатки в том, что вы заменяете строку каждый раз (при каждом запросе).Таким образом, вы должны кэшировать его в памяти, или:

b) сделать то же самое, что и а) и использовать вторую таблицу базы данных или даже файлы для хранения «окончательной» (полностью замененной) версии ваших строк HTML.Затем напишите небольшой генераторный скрипт, который берет spaceholder-версию из a), заполняет значения и затем сохраняет их в таблице / файле из b).Тогда вашему приложению необходимо использовать последние строки из этой таблицы / файла.Вам нужно только запускать этот скрипт каждый раз при смене хоста и порта.

0 голосов
/ 22 марта 2011

Вы можете попробовать

<img src="http://<%=request.getServerName()%>:request.getServerPort()/images/car.png" />

Проверьте Java документы Кроме того, вы можете попробовать

<% @page import="java.net.InetAddress" %>
<%
InetAddress ia = InetAddress.getLocalHost();
String hostName = ia.getHostName();
%>
...