Загрузка HTML с помощью XMLHttpRequest

Последнее обновление: 04.11.2023

Нередко в коде страницы требуется получить с сервера некоторый код HTML. Например, страница может представлять одностраничный сайт, который через ajax запрос загружает необходимый html-код и вставляет на страницу. Поэтому рассмотрим, как через AJAX загрузить код html.

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

Итак, определим для проекта на жестком диске папку, в которой создадим три файла:

  • index.html: главная страница приложения

  • home.html: страница с кодом html, который мы будем загружать через AJAX

  • server.js: файл приложения сервера, который будет использовать Node.js

Определение сервера

Файл server.js будет представлять код сервера Node.js. Определим в нем следующий код:

const http = require("http");
const fs = require("fs");
    
http.createServer((request, response)=>{
    // получаем путь после слеша, слеш - первый символ в пути
    let filePath = request.url.substring(1);
    // если пустой путь, отправляем главную страницу index.html
    if(!filePath) filePath = "index.html";  
    // в качестве типа ответа устанавливаем html
    response.setHeader("Content-Type", "text/html; charset=utf-8;");
    fs.readFile(filePath, (error, data)=>{
        if(error){                              // если ошибка
            response.statusCode = 404;
            response.end("<h1>Resourse not found!</h1>");
        }   
        else{
            response.end(data);
        }
    });
}).listen(3000, ()=>console.log("Сервер запущен по адресу http://localhost:3000"));

Вкратце пробежимся по коду. Сначала подключаются пакеты с функциональностью, которую мы собираемся использовать:

const http = require("http");	// для обработки входящих запросов
const fs = require("fs");		// для чтения файлов с жесткого диска

Для создания сервера применяется функция http.createServer(). В эту функцию передается функция-обработчик, которая вызывается каждый раз, когда к серверу приходит запрос. Эта функция имеет два параметра: request (содержит данные запроса) и response (управляет отправкой ответа).

В функции-обработчике с помощью свойства request.url мы можем получить путь к ресурсу, к которому пришел запрос. Нам надо обрабатывать запросы к страницам "index.html" и "home.html" (а в перспективе к любым другим страницам html). Путь всегда начинается со слеша "/". Например, запрос к странице "home.html" будет представлять путь "/home.html". Соответственно, чтобы получить из запрошенного пути путь к файлам на жестком диске, нам надо убрать начальный слеш:

let filePath = request.url.substring(1);

Однако если запрос обращен к корню сайта, то путь состоит только из одного слеша - "/". Соответственно, если мы удалим этот слеш, то получим пустую строку. Поэтому если запрос идет к корню веб-приложения, то будем считать что запрос идет к главной странице - index.html:

if(!filePath) filePath = "index.html";

И поскольку в нашем случае ответ сервера будет представлять код html, то с помощью метода setHeader() устанавливаем для заголовка "Content-Type" значение "text/html":

response.setHeader("Content-Type", "text/html; charset=utf-8;");

То есть ответ сервера будет представлять html.

Далее с помощью функции fs.readFile считываем файл, к которому идет запрос. Первый параметр функции - адрес файла (в данном случае предполагается, что файл находится в одной папке с файлом сервера server.js). Второй параметр - функция, которая вызывается после считывания файла и получет его содержимое через свой второй параметр data. Вполне возможно, что запрошенного файла не окажется, и в этом случае отправляем ошибку 404:

fs.readFile(filePath, (error, data)=>{
    if(error){                              // если ошибка
        response.statusCode = 404;
        response.end("<h1>Resourse not found!</h1>");
    } 

Если ошибки нет, файл найден и успещно считан, то отправляем параметр data, который содержит данные файла:

else{
    response.end(data);
}

В конце с помощью функции listen() запускаем веб-сервер на 3000 порту. То есть сервер будет запускаться по адресу http://localhost:3000/

Определение кода html для загрузки

Файл home.html будет содержать простенький код, который будет загружаться веб-страницей. Пусть это будет следующий код:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Home Page</title>
</head>
<body>
    <h1>Home Page</h1>
    <p>Home Page Text</p>
</body>
</html>

Определение главной страницы и загрузка данных

Теперь определим код главной страницы index.html, которая будет загружать страницу home.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>METANIT.COM</title>
</head>
<body>
<script>
const xhr = new XMLHttpRequest();
xhr.onload = () => {                        // обработчик получения ответа сервера
    if (xhr.status == 200) {                // если код ответа 200
        const html = xhr.responseText;      // получаем ответ
        console.log(html);      // выводим полученный ответ на консоль браузера
    } else {                                // иначе выводим текст статуса
        console.log("Server response: ", xhr.statusText);
    }
};
xhr.open("GET", "/home.html");                  // GET-запрос к ресурсу /home.html
xhr.setRequestHeader("Accept", "text/html");    // принимаем только html
xhr.send();     // выполняем запрос
</script>
</body>
</html>

В обработчике загрузке xhr.onload получаем текст ответа через xhr.responseText и выводим ответ на консоль.

Теперь в консоли перейдем к папке сервера с помощью команды cd и запустим сервер с помощью команды node server.js

C:\app>node server.js
Сервер запущен по адресу http://localhost:3000

После запуска сервера мы можем перейти в браузере по адресу http://localhost:3000, нам отобразится страница, в javascript-коде которой произойдет обращение к странице "home.html". Код javascript получит эту страницу и выведет ее содержимое на консоль:

Получение кода html в ajax-запросе с помощью XMLHttpRequest в javascript

Управление html-содержимым

В примере выше мы получали содержимое страницы как обычный текст. Однако так как этот текст фактически содержит разметку HTML, то мы можем загрузить его на веб-страницу. Так, изменим код страницы index.html следующим образом:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>METANIT.COM</title>
</head>
<body>
<div id="content"></div>
<script>
const contentDiv = document.getElementById("content");  // элемент для загрузки html
const xhr = new XMLHttpRequest();

xhr.onload = () => { 
    if (xhr.status == 200) {
        contentDiv.innerHTML = xhr.responseText;  // выводим полученный ответ в contentDiv
    } else {                                // иначе выводим текст статуса
        console.log("Server response: ", xhr.statusText);
    }
};
xhr.open("GET", "/home.html");                  // GET-запрос к ресурсу /home.html
xhr.setRequestHeader("Accept", "text/html");    // принимаем только html
xhr.send();     // выполняем запрос
</script>
</body>
</html>

В данном случае загружаем полученный код страницы "home.html" в элемент c id=content

Загрузка кода html на веб-страницу в ajax-запросе с помощью XMLHttpRequest в javascript

Однако проблема в данном случае состоит в том, что код страницы "home.html" кроме собственно некоторого содержимого также содержит элементы head, title, метаописания страницы с помощью тегов <meta>. Эти элементы нет смысла загружать на другую веб-страницу. Либо мы хотим загрузить какой-то определенный элемент со страницы "home.html", а не весь ее код. В этом случае мы можем получить ответ через свойство responseXML и затем манипулировать ответом как стандартным документом html. Например, изменим код javascript следующим образом:

const contentDiv = document.getElementById("content");

const xhr = new XMLHttpRequest();
xhr.onload = () => {                        // обработчик получения ответа сервера
    if (xhr.status == 200) {
        // загружаем только содержимое элемента body
        contentDiv.innerHTML = xhr.responseXML.body.innerHTML;
    } else {                                
        console.log("Server response: ", xhr.statusText);
    }
};
xhr.open("GET", "/home.html");                  // GET-запрос к ресурсу /home.html
xhr.responseType = "document";              // устанавливаем тип ответа
xhr.setRequestHeader("Accept", "text/html");    // принимаем только html
xhr.send();     // выполняем запрос

Здесь следует отметить два момента. Прежде всего устанавливаем для ответа тип "document":

xhr.responseType = "document"; 

Это позволит нам получить ответ как объект типа Document, аналогичный тому, что представляет свойство document на веб-странице.

Чтобы получить ответ в виде html/xml используем свойство responseXML. И далее, поскольку это свойство представляет объект Document, используем свойство body для обращения к непосредственному содержимому страницы:

contentDiv.innerHTML = xhr.responseXML.body.innerHTML;

В результате в contentDiv будет загружено содержимое элемента body страницы "home.html".

Подобным образом можно обращаться к другим свойствам объекта Document. Например, получим заголовок:

document.title = xhr.responseXML.title;

Или загрузим на страницу только текст из заголовка <ht1>:

contentDiv.innerHTML =  xhr.responseXML.querySelector("h1").textContent; 

Динамическая загрузка компонентов

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

  • server.js: файл приложения сервера на Node.js

  • index.html: главная страница приложения

  • home.html: файл компонента home

  • about.html: файл компонента about

  • contact.html: файл компонента contact

Файл приложения сервера на Node.js - server.js остается тем же, что был определен выше в данной статье.

Пусть файл home.html содержит какой-нибудь простейший код типа следующего:

<h1>Home Page</h1>
<p>Home Page Text</p>

Файл about.html пусть выглядит аналогичным образом:

<h1>About Page</h1>
<p>About Page Text</p>

И код файла contact.html:

<h1>Contact Page</h1>
<p>Contact Page Text</p>

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

На главной странице index.html определим следующий код:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>METANIT.COM</title>
</head>
<body>
<nav><a href="home">Home</a> | <a href="about">About</a> | <a href="contact">Contact</a></nav>
<div id="content"></div>
<script>
const contentDiv = document.getElementById("content");

function loadContent(fileName){
    const xhr = new XMLHttpRequest();
    xhr.onload = () => {
        if (xhr.status == 200) {
            contentDiv.innerHTML = xhr.responseText; // xhr.responseXML.body.innerHTML;
            document.title = fileName;
        }
    };
    xhr.open("GET", fileName + ".html");              // GET-запрос по адресу ссылки
    xhr.setRequestHeader("Accept", "text/html");    // принимаем только html
    xhr.send();     // выполняем запрос
}

// устанавливаем обработчик нажатия для кнопок
const links = document.getElementsByTagName("a"); 
for (let i = 0; i < links.length; i++) {
    links[i].addEventListener("click", (e)=>{
        loadContent(links[i].getAttribute("href"));
        e.preventDefault();
    });  
} 
// по умолчанию загружаем компонент home
loadContent("home");
</script>
</body>
</html>

Здесь для навигации по компонентам на страницу помещаем ряд ссылок:

<nav><a href="home">Home</a> | <a href="about">About</a> | <a href="contact">Contact</a></nav>

Адрес каждой такой ссылки совпадает с названием страницы соответствующего компонента без расширения ".html".

Каждый из компонентов будет загружаться на странице в элемент с id="content", который получаем в коде JavaScript в константу contentDiv:

const contentDiv = document.getElementById("content");

Также в коде JavaScript для каждой ссылки устанавливаем обработчки, в котором вызываем функцию loadContent и в которую передаем значение атрибута href ссылки - то есть адрес компонента

const links = document.getElementsByTagName("a"); 
for (let i = 0; i < links.length; i++) {
    links[i].addEventListener("click", (e)=>{
        loadContent(links[i].getAttribute("href"));
        e.preventDefault();
    });  
} 

В функции loadContent используем адрес ссылки для отправки ajax-запроса, а ответ (полученный html) загружаем в элемент contentDiv

contentDiv.innerHTML = xhr.responseText; // xhr.responseXML.body.innerHTML;

При загрузке страницы сразу загружаем код компонента home, как компонента по умолчанию:

loadContent("home");

Таким образом, на главной странице мы сможем обращаться к конкретным компонентам, переходя по ссылкам:

Динамическая загрузка компонентов на веб-страницу в ajax-запросе с помощью XMLHttpRequest в javascript
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850