如何在Javascript / Node.js Azure函数

时间:2019-06-25 11:39:19

标签: javascript node.js azure-functions jsdom

我正在尝试在Azure函数中使用外部javascript(javascript / node.js风格)。由于外部javascript(我需要使用kendo)取决于DOM和窗口,因此我尝试使用JSDOM(但如果有更好/更简便的选择,则不必使用JSDOM)。

这是我所拥有的简化示例:

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    var html = '<!DOCTYPE html>'
    + '<html>'
    +   '<head>'
    +       '<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>'
    +       '<script src="https://kendo.cdn.telerik.com/2019.2.514/js/kendo.all.min.js"></script>'
    +   '</head>'
    +   '<body>'
    +       '<script>'
    +           'var myDiv = document.createElement("div");'        
    +           'myDiv.innerHTML = "Hello World";'
    +           'document.body.appendChild(myDiv);'
    +       '</script>'
    +   '</body>'
    + '</html>'
    ;

    var jsdom = require('jsdom');
    const { JSDOM } = jsdom;

    const dom = new JSDOM(html, {
        runScripts: "dangerously",
        resources: "usable"
    });

    var test = dom.serialize();
    context.log(test);

    context.res = {
        body: test
    };
};

运行此Azure函数时,它应包括jquery和kendo并创建一个包含“ Hello World”的div。但是,这不起作用。

仅当我注释掉其中一个时,才会执行创建Hello World div的脚本

+       '<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>'
+       '<script src="https://kendo.cdn.telerik.com/2019.2.514/js/kendo.all.min.js"></script>'

resources: "usable"

但是我不能使用jquery和kendo。

根据此jsdom documentation,参数资源:“可用”应该可以解决问题,但由于某些原因,它不能正常工作。

我正在使用“ jsdom”:“ ^ 15.1.1”

更新: 我尝试了一种解决方法,添加了如下脚本:

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    var html = '<!DOCTYPE html>'
    + '<html>'
    +   '<head>'
    +   '</head>'
    +   '<body>'
    +       '<script>'
    +           'var myDiv = document.createElement("div");'        
    +           'myDiv.innerHTML = "Hello World";'
    +           'document.body.appendChild(myDiv);'
    +           'var scriptTag = document.createElement("script");'        
    +           'scriptTag.innerHTML = window.jqueryString;'
    +           'document.head.appendChild(scriptTag);'
    +       '</script>'
    +   '</body>'
    + '</html>'
    ;

    var jsdom = require('jsdom');
    const { JSDOM } = jsdom;

    var fs = require("fs");
    global.jqueryString = fs.readFileSync(__dirname + '//jquery.js').toString();
    //context.log(jqueryString);

    const dom = new JSDOM(html, {
        runScripts: "dangerously"
    });

    var test = dom.serialize();
    context.log(test);


    context.res = {
        body: test
    };
};

这是向标头添加脚本标记,但是innerHTML是“未定义”而不是jqueryString。 在JSDOM之外(请参见注释行),记录jqueryString将按预期显示jquery.js的内容。但是在JSDOM内部,该变量似乎不可用。如何将jqueryString传递给JSDOM?

2 个答案:

答案 0 :(得分:1)

我仔细检查了jsdom节点程序包,然后发现功能Loading subresources需要一个无头浏览器,例如通过karma的无头Chrome。但是,由于Azure Web App sandbox中的Win32k.sys (User32/GDI32) Restrictions,它无法在Windows Azure应用服务上正常运行,因为无头浏览器需要GDI支持。

enter image description here

因此,我建议您按照Azure Functions Core Tools官方文档所述,通过Create your first function hosted on Linux using Core Tools and the Azure CLI (preview)对其进行重建,将功能迁移到Linux的Azure Functions(基于Docker容器)。或者您必须使用Windows,Azure Windows VM将是您的最佳选择。

希望有帮助。

答案 1 :(得分:0)

使用@PeterPan的输入,我设法使用带有{strong> Docker based Azure functionPuppeteer解决了我的问题。

基于Docker的FunctionApp初始化:

func init MyFunctionProj --docker(选择->节点-> javascript)

编辑MyFunctionProj \ Dockerfile以使用estruyf/azure-function-node-puppeteer和fs:

FROM estruyf/azure-function-node-puppeteer
RUN npm i fs
COPY . /home/site/wwwroot

将fs添加到MyFunctionProj \ package.json中的依赖项:

"dependencies": {
    "fs": "0.0.1-security"
  }

创建HttpTrigger函数:

cd MyFunctionProj
func new --name MyHttpTrigger --template "HttpTrigger"

授予对功能的访问权限:

在MyFunctionProj \ MyHttpTrigger \ function.json中设置"authLevel": "anonymous"(原因请参见here。)

创建MyFunctionProj \ MyHttpTrigger \ content.html文件:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>ContentHtml</title>

    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="https://kendo.cdn.telerik.com/2019.2.514/js/kendo.all.min.js"></script>
</head>
<body>

<script>
    $(document).ready(function() {
       var myComputationResult = .... // use included scripts to perform computation
       $("#resultData").html(JSON.stringify(myComputationResult));
    });
</script>
<div id="resultData"></div>
</body>
</html>

在MyFunctionProj \ MyHttpTrigger \ index.js中编辑函数逻辑(基于this):

const puppeteer = require('puppeteer');
const fs = require("fs");

module.exports = async (context, req) => {    
    const browser = await puppeteer.launch({
        args: [
            '--no-sandbox',
            '--disable-setuid-sandbox'
        ]
    });

    var contentHtml = fs.readFileSync(__dirname + '//content.html', 'utf8');

    const page = await browser.newPage();
    await page.goto(`data:text/html,${contentHtml}`, { waitUntil: 'networkidle2' });
    const resultData = await page.evaluate(() => document.querySelector('#resultData').innerHTML);
    await browser.close();

    context.res = {
        // status: 200, /* Defaults to 200 */
        body: `Result: ${resultData}`
    };
};

构建docker映像:

docker build --tag <docker-id>/mydockerimage:v1.0.0 .

运行docker映像:

docker run -p 8080:80 -it <docker-ID>/mydockerimage:v1.0.0

在浏览器中测试本地功能图像:

http://localhost:8080/api/MyHttpTrigger

将映像推送到Docker Hub:

docker login --username <docker-id>
docker push <docker-id>/mydockerimage:v1.0.0

在线创建一个新的Azure Function,并按照here中所述使用Docker Hub中的映像。