繁体   English   中英

如何在 Marklogic 的 Optic API 查询中使用由用户在 Web 应用程序中设置的参数值?

[英]How do I use a parameter value, set by a user in a web application, in an Optic API query in Marklogic?

块引用

我有一个 Web 应用程序(用 js 编写),用户可以在其中输入名称(以及其他条件)并执行针对 ML 数据库的搜索,以及与该名称(或其他搜索条件)相关联的一些数据的表格表示) 被退回。 在开发的第一阶段,我编写了 optic api 查询,其中 name 的值硬编码在查询的 where 语句中。 我这样做是为了测试 REST api 是否正确调用了查询等。一切正常,我可以看到在 Web 应用程序中返回的硬编码名称的正确结果。 现在我想将用户提供的 name 值传递给 Optic api 查询 (EntityInformation_Optic_API_Query.json) 以替换 where 语句中的硬编码值。 我该怎么做呢? 提前致谢。


所有者编辑

该应用程序是用 PHP 编写的,我复制了下面的代码。 在此您可以看到调用 optic api 查询的位置以及构建参数的位置。

<?php
if (!defined('RSS_BASE_URL')) exit;

use MarkLogic\MLPHP as MLPHP;

function rss_api_call($json, $params = array(), $resource = 'rows', $verb = 'POST')
{
    $json = __DIR__ . '/json/' . $json;

    if (!file_exists($json)) return false;

    $request = new MLPHP\RESTRequest('POST', 'rows', $params, file_get_contents($json), array('Content-type' => 'application/json'));
    $response = rss_get_client()->send($request);

    return json_decode($response->getBody());
}

function rss_api_entities()
{
    $params = array();

    return rss_api_call('EntityInformation_Optic_API_Query.json', $params);
    //return (empty($params)) ? '' : rss_api_call('EntityInformation_Optic_API_Query.json', $params);
}

function rss_api_search()
{
    $params = array();

    if (isset($_POST['companyname']) && !empty($_POST['companyname']))
    {
        $params['CompanyName'] = htmlspecialchars($_POST['companyname']);
    }

    if (isset($_POST['EIN']) && !empty($_POST['ein']))
    {
        $params['EIN'] = htmlspecialchars($_POST['ein']);
    }

    if (isset($_POST['city']) && !empty($_POST['city']))
    {
        $params['EntityCity'] = htmlspecialchars($_POST['city']);
    }

    if (isset($_POST['state']) && !empty($_POST['state']))
    {
        $params['EntityState'] = htmlspecialchars($_POST['state']);
    }

    if (isset($_POST['zip']) && !empty($_POST['zip']))
    {
        $params['EntityZip'] = htmlspecialchars($_POST['zip']);
    }

    return rss_api_call('SearchResults_Optic_API_Query.json', $params);
    //return (empty($params)) ? '' : rss_api_call('SearchResults_Optic_API_Query.json', $params);
}

function rss_asset_path($path, $file_name)
{
    global $rss_manifest;

    if (empty($rss_manifest))
    {
        ob_start();

        include(__DIR__ . '/../manifest.json');

        $rss_manifest = json_decode(ob_get_clean(), true);
    }

    if (isset($rss_manifest[$file_name]))
    {
        $file_name = $rss_manifest[$file_name];
    }

    return RSS_ASSET_PATH . $path . '/' . $file_name;
}

function rss_box($title, $content)
{
    echo '<div class="rss-box">' .
        '<div class="rss-box-title">' . $title . '</div>' .
        '<div class="rss-box-content">' . $content . '</div>' .
        '</div>';
}

function rss_get_client()
{
    $mlphp = new MLPHP\MLPHP(array
    (
        'host' => RSS_API_HOST,
        'port' => RSS_API_PORT,
        'version' => RSS_API_VERSION,
        'username' => RSS_API_USERNAME,
        'password' => RSS_API_PASSWORD
    ));

    return $mlphp->getClient();
}

function rss_hidden_search_fields()
{
    echo '<div class="rss-hidden">';

    $fields = array('debug', 'companyname', 'ein', 'city', 'state', 'zip');

    foreach ($fields as $field)
    {
        echo (isset($_POST[$field])) ? '<input name="' . $field . '" type="hidden" value="' . htmlspecialchars($_POST[$field]) . '" />' : '';
    }

    if (!empty($_POST['social']))
    {
        $social = (is_array($_POST['social'])) ? $_POST['social'] : array($_POST['social']);

        foreach ($social as $social_network)
        {
            echo '<input name="social[]" type="hidden" value="' . htmlspecialchars($social_network) . '" />';
        }
    }

    echo (empty($_POST['social-select-all'])) ? '' : '<input name="social-select-all" type="hidden" value="1" />';
    echo '</div>';
}



Part of the EntityInformation_Optic_API_Query.json is below
-----

edit (information from a comment below):

The request will be a POST to /v1/rows. Does the following payload look correct? 

```javascript
{
    "$optic": {
        "ns": "op",
        "fn": "operators",
        "args": [
            {
                "ns": "op",
                "fn": "from-view",
                "args": [ "TestSchema", "SUT", null, null ]
            },
            {
                "ns": "op",
                "fn": "where",
                "args": [
                    {
                        "ns": "op",
                        "fn": "eq",
                        "args": [
                            {
                                "ns": "op",
                                "fn": "col",
                                "args": [ "CompanyName" ]
                            },
                            "${req.params.CompanyName}"
                        ]
                    }
                ]
            }

我相信您需要使用“绑定”参数。 所以你的计划看起来像这样:

{
  "$optic": {
    "ns": "op",
    "fn": "operators",
    "args": [
      {
        "ns": "op",
        "fn": "from-view",
        "args": [
          "TestSchema",
          "SUT",
          null,
          null
        ]
      },
      {
        "ns": "op",
        "fn": "where",
        "args": [
          {
            "ns": "op",
            "fn": "eq",
            "args": [
              {
                "ns": "op",
                "fn": "col",
                "args": [
                  "CompanyName"
                ]
              },
              {
                "ns": "op",
                "fn": "param",
                "args": [
                  "companyName"
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

然后当您将其发布到 /v1/rows 时,您需要设置companyName绑定参数和类型。 因此,将以下参数添加到您的 POST:

bind:companyName=${req.params.CompanyName}
bind:companyName:type=xs:string

假设${req.params.CompanyName}包含用户传递的公司名称值。

作为旁注,手动处理序列化的光学计划可能很困难。 我建议你把它放在一个 REST 扩展后面,只传递参数。 如果您真的希望将 Optic 计划保留在您的中间层,您始终可以使用 MarkLogic 的查询控制台来生成计划,并在您希望具有参数化值的地方使用正确的op.param()调用。 IE类似:

 const op = require('/MarkLogic/optic'); const plan = op .fromView("TestSchema", "SUT") .where( op.eq( op.col("CompanyName"), op.param("companyName") ) ) plan.export()

这取决于您如何设置应用程序。

REST API

如果您的代码将成为 REST API 扩展,则您编写的函数将有一个params参数。 对于 JavaScript,这将是一个对象。 请参阅JavaScript 资源扩展接口 从文档的那部分:

如果请求是 PUT /v1/resource/my-ext?rs:p=1&rs:p=2 ,则params.p值为 ["1", "2"]。

主模块

如果客户端将通过常规(非 REST)主模块访问您的代码,则使用xdmp.getRequestField


编辑:我用您评论中的更多信息更新了您的问题。 在我看来,您有一个中间层,它从客户端(浏览器)获取参数并使用它们来构建要传递给/v1/rows的查询。 看起来"${req.params.CompanyName}"旨在进行插值,以便您的中间层获得req.params.CompanyName的值,然后将其放入发送给 MarkLogic 的字符串中。

是否有可能将"${req.params.CompanyName}"添加到带有完整引号的字符串中,以便中间层无法进行插值? 如果您可以提供有关如何构建/v1/rows的有效负载的更多信息,我们可能会提供更多帮助。

对于 Java 或 Node.js Web 应用程序,最好的方法可能是编写一个函数,该函数接受该值并构建并返回一个 Optic 查询。

在其他环境中,使用 JSON 表示并插入值是最安全的。

尽管有时难以调试,但可以通过转义将 Optic 查询的 JSON 序列化组装为字符串。 在 MarkLogic enode 上,JSON 被解析为 JSON 而不是评估,因此不存在注入攻击的风险,但解析失败是可能的。

希望有所帮助,

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM