Выразительный JavaScript (Хавербеке) - страница 224

, которая создаёт такой обратный вызов.

Вот обработчик запросов >PUT:

>methods.PUT = function(path, respond, request) {

>  var outStream = fs.createWriteStream(path);

>  outStream.on("error", function(error) {

>    respond(500, error.toString());

>  });

>  outStream.on("finish", function() {

>    respond(204);

>  });

>  request.pipe(outStream);

>};

Здесь нам не нужно проверять существование файла – если он есть, мы его просто перезапишем. Опять мы используем >pipe для передачи данных из читаемого потока в записываемый, в нашем случае – из запроса в файл. Если создать поток не удаётся, создаётся событие >“error”, о чём мы сообщаем в ответе. Когда данные переданы успешно, >pipe закроет оба потока, что приведёт к запуску события >“finish”. А после этого мы можем отчитаться об успехе с кодом 204.

Полный скрипт сервера лежит тут: eloquentjavascript.net/code/file_server.js. Его можно скачать и запустить через Node. Конечно, его можно менять и дополнять для решения упражнений или экспериментов.

Утилита командной строки >curl, общедоступная на unix-системах, может использоваться для создания HTTP запросов. Следующий фрагмент тестирует наш сервер. >–X используется для задания метода запроса, а >–d для включения тела запроса.

>$ curl http://localhost:8000/file.txt

>File not found

>$ curl -X PUT -d hello http://localhost:8000/file.txt

>$ curl http://localhost:8000/file.txt

>hello

>$ curl -X DELETE http://localhost:8000/file.txt

>$ curl http://localhost:8000/file.txt

>File not found

Первый запрос к >file.txt завершается с ошибкой, поскольку файла ещё нет. Запрос >PUT создаёт файл, и глядите-ка – следующий запрос его успешно получает. После его удаления через >DELETE файл снова отсутствует.

Обработка ошибок

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

Что будет, когда что-то реально выбросит исключение в системе? Мы не используем блоки >try, потому оно будет передано на самый верх стека вызовов. В Node это приводит к прекращению выполнения программы и выводу информации об исключении (вместе с отслеживанием стека) на стандартный вывод.

Поэтому наш сервер будет падать при возникновении проблем в коде – в отличие от проблем с асинхронностью, которые будут переданы как аргументы в функции вызова. Если нам надо обрабатывать все исключения, возникающие при обработке запроса, чтобы мы точно отправили ответ, нам надо добавлять блоки