CoffeeScript в сценарии оболочки, запускаемом Apache (как CGI)

Следуя совету здесь я могу получить сценарий оболочки на JavaScript, который запускается под node.js и печатает немного hello world html:

test.cgi
-------
#!/usr/local/bin/node

console.log("Content-Type: text/html; charset=utf-8\n");
console.log("<html><body><h1>hello node.js world</h1></body></html>");
-------

И запустить его:

$ ./test.cgi
Content-Type: text/html; charset=utf-8

<html><body><h1>hello node.js world</h1></body></html>

Он также работает должным образом в Apache и отображает ожидаемый HTML-код в браузере.

Теперь перейдем к CoffeeScript (обратите внимание на прекрасную документацию в тройных кавычках в стиле Python):

ctest.cgi
-------
#!/usr/bin/env coffee

console.log("Content-Type: text/html; charset=utf-8\n");
console.log('''<html><body><h1>hello CoffeeScript world
</h1></body></html>''');
-------

Это работает при локальном запуске:

$ ./ctest.cgi
Content-Type: text/html; charset=utf-8

<html><body><h1>hello CoffeeScript world
</h1></body></html>

Но не в Апаче:

Internal Server Error

Почему это не работает?


person Jared Updike    schedule 13.03.2011    source источник


Ответы (5)


Я попытался исправить это, реконструировав command.js из CoffeeScript и запустив свой кофейный скрипт (ctest.cgi выше) напрямую, через следующий скрипт оболочки JavaScript node.js:

drip
-------
#!/usr/local/bin/node

var fs = require('fs');
var cs = require('/usr/local/lib/coffee-script/lib/coffee-script');
var args = process.argv;
var fname = args[2];
if (fname)
{
    fs.readFile(fname, function (err, data) {
      if (err) throw err;
      var text = data.toString(); //console.log(data.toString());
      cs.run(text, {'filename':fname, 'bare':undefined});
    });
}
-------

Я поместил это в /usr/local/bin/drip, и теперь я могу запустить ctest.cgi с небольшим изменением в верхней строке:

#!/usr/bin/env /usr/local/bin/drip

Теперь я могу взламывать CGI-скрипты CoffeeScript и просто перезагружать в своем браузере вместо того, чтобы вручную вызывать компилятор CoffeeScript при изменении файлов .coffee.

person Jared Updike    schedule 13.03.2011
comment
Вероятно, это правильное направление, если вы собираетесь использовать CoffeeScript для CGI в критически важной для производительности среде, поскольку, если вы каждый раз запускаете скрипт с coffee, вы каждый раз берете на себя накладные расходы на компиляцию CoffeeScript. Вместо этого вы можете расширить приведенный выше сценарий, чтобы он компилировался в файл .js, если такой файл не существует или отметка времени в файле .coffee более поздняя, ​​а затем запускает файл .js. - person Trevor Burnham; 13.03.2011
comment
@Trevor: Компиляция - действительно отличная идея. Кроме того, я только что увидел, что могу напечатать некоторый базовый заголовок http в блоке catch, чтобы трассировки исключений печатались в браузере, вместо того, чтобы отслеживать /var/log/apache2/error_log, когда у меня есть синтаксические ошибки в моих сценариях. Кстати, мой подход не так критичен к производительности, но, скорее, я хотел попробовать CoffeeScript в качестве замены моим CGI-скриптам на Python в рамках плана по полной замене Python автономным JS, работающим в браузере, поскольку CoffeeScript ЕСТЬ JavaScript — такой же красивый, как Python. - person Jared Updike; 13.03.2011
comment
На самом деле, если я добавлю подход к компиляции, это может помочь решить другую проблему, а именно: позволить CGI-скриптам кофе «требовать» другие файлы .coffee в той же папке (я бы добавил ту же логику для повторной компиляции требуемых .js, если файлы . метка времени приготовления кофе не совпала). Если у меня получится что-то полезное, я опубликую это на github. - person Jared Updike; 13.03.2011

Вы, наверное, уже думали об этом, но: Вы пробовали заменить

#!/usr/bin/env coffee

с абсолютной ссылкой на то, где находится coffee? env зависит от переменной окружения PATH, а PATH при запуске ./ctest.cgi не обязательно совпадает с Apache.

person Trevor Burnham    schedule 13.03.2011
comment
Я пробовал это, но сценарий /usr/local/bin/coffee использует тот же бит узла /usr/bin/env, который определен для моего пользователя, но не в контексте пользователя, в котором работает Apache. Теперь я только что попытался изменить первую строку кофе на абсолютную ссылку на узел, но хаки пути в сценарии кофе не могут быть связаны с правильным местоположением в /usr/local/lib/coffee-script/lib, поэтому еще больше модификаций кофе потребуется скрипт, который является сущностью моего скрипта капель выше. - person Jared Updike; 13.03.2011
comment
АА, вижу. Что ж, я не эксперт по Apache, но пробовали ли вы использовать mod_env установить переменную PATH так, чтобы она указывала и на coffee, и на node? - person Trevor Burnham; 13.03.2011

Вот моя установка, кому интересно.

Это очень плохо для производительности!

~/coffee
------
#!/usr/bin/perl 

# this is coffee runner!

print ` PATH="\$PATH:~/www/cgi-bin/bin" ; ~/www/cgi-bin/bin/node_modules/coffee-script/bin/coffee $ARGV[0] 2>&1 `;
------

У меня нет необходимости изменять мою серверную среду, поэтому я добавляю здесь пути к своим узлам. Однако я могу настроить обработчик в .htaccess:

~/dir/.htaccess
------
AddHandler cgi-script .litcoffee
DirectoryIndex cv.litcoffee
------

Это означает, что я могу работать с CGI и подавать кофе для браузера :-) Очень неэффективно, но все равно мало кто заходит на мой сайт.

Тогда каждый из моих скриптов выглядит примерно так...

~/web/ascript.litcoffee
------
#!/usr/bin/perl /home/jimi/coffee

This is literate coffeescript!

    module.paths.push "/home/jimi/www/cgi-bin/bin/node_modules"
    require "coffee-script"

This is a wee module I wrote for spewing tags, with content and attributes

    global[k.toUpperCase()] = v for k,v of require './html.litcoffee'

It also provides a header function, but I'm going to move that to a CGI module when I get around to it.

    console.log CGI_HEADER()

Now we can put something to the browser.

    console.log HTML [
        HEAD [
            META {charset:"utf-8"}
            SCRIPT [],
                src : "https://raw.github.com/jashkenas/coffee-script/master/extras/coffee-script.js"
            SCRIPT [],
                src : "runsonclient.coffee"
                type    : "text/coffeescript"
            LINK
                rel : "stylesheet"
                href    : "mystyles.css"
            TITLE "A page title"
        ]
        BODY [
            H1 "a page title"
            INPUT 
                id     : "myinput"
                type   : "text"
            SVG
                id     : "mysvg"
                width  : "80%"
                height : "20"
            DIV
                id     : "mydiv"
        ]
    ]
------

Я знаю, что это некрасиво, но это работает. И запуск из скрипта (хотя, по общему признанию, это не обязательно должен быть Perl!) позволяет 2>&1, поэтому все мои ошибки попадают на экран, если только мой заголовок не печатается .... но Джаред Апдайк уже решил это с помощью блока try .

person user2967328    schedule 08.11.2013
comment
Я пытался отредактировать и обновить это, но оно было отклонено... хотел поделиться обновлением сценария: - person user2967328; 25.10.2016

Я понятия не имею, почему кофе не работает, но возможное (и очень простое) решение — поместить ваш код в отдельный файл (test.coffee) и выполнить требование:

#!/usr/local/bin/node

require('coffee-script')
require('./test')

(после запроса coffee-script расширение автоматически регистрируется)

person Ricardo Tomasi    schedule 14.03.2011
comment
Я проверил это (вставил это в rtest.cgi), и он прекрасно работает из командной строки под моим пользователем, но не работает при загрузке в качестве сценария CGI под Apache (другие сценарии .cgi в той же папке работают нормально). В журнале ошибок отображается исключение: Не удается найти модуль «coffee-script». В целом это кажется правильным/лучшим подходом, если мы можем сообщить узлу о coffee-script с помощью каких-либо других средств, кроме переменных env, или путем правильного определения переменных env. - person Jared Updike; 14.03.2011
comment
модули устанавливаются по пользовательскому пути (~/.node_modules). попробуйте установить переменную среды NODE_PATH. - person Ricardo Tomasi; 15.03.2011

Я попытался обновить свой ответ, но он был отклонен, и в некоторых советах было сказано добавить это как отдельный ответ...

Я только что обновил это до сценария оболочки с компиляцией, если более новая функциональность:

#!/bin/sh
CS=$1        # the coffeescript to be run
# the following works because (my) apache runs in the script's directory and passes just the filename (no path)
# if would be safer to test that this is the case, or make sure the dot is added to the filename part
JS=.$CS.cjs  # the compiled javascript
CE=.$CS.cerr # compiler errors
PATH="$PATH:/home/jimi/www/cgi-bin/bin:/home/jimi/www/cgi-bin/bin/node_modules/coffee-script/bin"
if [ ! -f $JS ] || [ $CS -nt $JS ] ; then
    coffee -c -p $1>$JS 2>$CE
fi
node $JS 2>&1   # runtime errors to browser
person user2967328    schedule 25.10.2016