Hyperledger Sawtooth - 提交交易时的预检错误

KBh*_*ray 4 hyperledger hyperledger-sawtooth

我正在尝试使用javascript向Hyperledger Sawtooth v1.0.1提交一个事务到在localhost上运行的验证器.邮寄请求的代码如下:

request.post({
        url: constants.API_URL + '/batches',
        body: batchListBytes,
        headers: { 'Content-Type': 'application/octet-stream' }
    }, (err, response) => {
        if (err) {
            console.log(err);
            return cb(err)
        }
        console.log(response.body);
        return cb(null, response.body);
    });
Run Code Online (Sandbox Code Playgroud)

从后端nodejs应用程序提交时会处理事务,但从OPTIONS http://localhost:8080/batches 405 (Method Not Allowed)客户端提交时会返回错误.这些是我尝试过的选项:

  1. Access-Control-Allow-*使用扩展名将标头插入响应中:响应仍然会产生相同的错误
  2. 删除自定义标头以绕过预检请求:这会使验证程序抛出错误,如下所示:

    ...
    sawtooth-rest-api-default | KeyError: "Key not found: 'Content-Type'"
    sawtooth-rest-api-default | [2018-03-15 08:07:37.670 ERROR    web_protocol] Error handling request
    sawtooth-rest-api-default | Traceback (most recent call last):
    ...
    
    Run Code Online (Sandbox Code Playgroud)

POST来自浏览器的未修改请求从验证器获取以下响应头:

HTTP/1.1 405 Method Not Allowed
Content-Type: text/plain; charset=utf-8
Allow: GET,HEAD,POST
Content-Length: 23
Date: Thu, 15 Mar 2018 08:42:01 GMT
Server: Python/3.5 aiohttp/2.3.2
Run Code Online (Sandbox Code Playgroud)

所以,我猜OPTIONS方法不在验证器中处理.GET添加CORS标头后,对状态的请求会很好.Sawtooth v0.8也没有遇到这个问题.

我正在使用docker来启动验证器,启动它的命令是LinuxFoundationX:LFS171x课程中给出的稍微修改过的版本.相关命令如下:

bash -c \"\
        sawadm keygen && \
        sawtooth keygen my_key && \
        sawset genesis -k /root/.sawtooth/keys/my_key.priv && \
        sawadm genesis config-genesis.batch && \
        sawtooth-validator -vv \
          --endpoint tcp://validator:8800 \
          --bind component:tcp://eth0:4004 \
          --bind network:tcp://eth0:8800
Run Code Online (Sandbox Code Playgroud)

有人可以指导我如何解决这个问题?

Zac*_*hal 7

CORS问题总是最好的.

什么是CORS?

您的浏览器试图保护用户不会将其定向到他们认为是API的前端的页面,但实际上是欺诈性的.只要网页尝试访问其他域上的API,该API就需要明确授予网页权限,否则浏览器将阻止该请求.这就是您可以从Node.js(无浏览器)查询API的原因,并且可以将REST API地址直接放入您的地址栏(同一域).然而,试图从去localhost:3000localhost:8008file://path/to/your/index.htmllocalhost:8008是会得到阻止.

为什么Sawtooth REST API不处理OPTIONS请求?

Sawtooth REST API不知道您要从哪个域运行您的网页,因此它无法明确地将其列入白名单.可以将所有域列入白名单,但这显然会破坏CORS可能给您的任何保护.不是试图为所有Sawtooth用户权衡这种方法的成本和收益,而是决定使REST API尽可能轻量级且安全无关.任何使用它的开发人员都应该将它放在代理服务器后面,并且他们可以在该代理层上做出他们需要的任何安全决策.

那么你如何解决它?

您需要设置一个代理服务器,将REST API和您的网页放在同一个域中.没有快速配置选项.您必须设置一个实际的服务器.显然有很多方法可以做到这一点.如果您已熟悉Node,则可以从Node.js提供页面,然后让Node服务器代理API调用.如果您已经运行了所有Sawtooth组件docker-compose,那么使用Docker和Apache可能会更容易.

使用Docker设置Apache代理

创建Dockerfile

在与Web应用程序相同的目录中,创建一个名为"Dockerfile"的文本文件(无扩展名).然后让它看起来像这样:

FROM httpd:2.4

RUN echo "\
LoadModule proxy_module modules/mod_proxy.so\n\
LoadModule proxy_http_module modules/mod_proxy_http.so\n\
ProxyPass /api http://rest-api:8008\n\
ProxyPassReverse /api http://rest-api:8008\n\
RequestHeader set X-Forwarded-Path \"/api\"\n\
" >>/usr/local/apache2/conf/httpd.conf
Run Code Online (Sandbox Code Playgroud)

这将做几件事.首先,它将httpd从DockerHub下载模块,DockerHub只是一个简单的静态服务器.然后我们使用一些bash为Apache的配置文件添加五行.这五行进口代理模块,告诉Apache我们要代理http://rest-api:8008/api路线,并设置X-Forwarded-Path页眉所以REST API可以正确地构建响应的URL.确保它rest-api与docker compose文件中的Sawtooth REST API服务的实际名称相匹配.

修改docker compose文件

现在,对于docker撰写的YAML文件,您正在运行Sawtooth,您希望在services键下添加一个新属性:

services:
  my-web-page:
    build: ./path/to/web/dir/
    image: my-web-page
    container_name: my-web-page
    volumes:
      - ./path/to/web/dir/public/:/usr/local/apache2/htdocs/
    expose:
      - 80
    ports:
      - '8000:80'
    depends_on:
      - rest-api
Run Code Online (Sandbox Code Playgroud)

这将构建位于./path/to/web/dir/Dockerfile(相对于docker compose文件)的Dockerfile ,并使用其默认命令运行它,即启动Apache.Apache将为所有文件提供服务/usr/local/apache2/htdocs/,因此我们将用于volumes将主机(即./path/to/web/dir/public/)上的Web文件的路径链接到容器中的该目录.这基本上是别名,因此如果您稍后更新Web应用程序,则无需重新启动此docker容器即可查看更改.最后,ports将服务器80放在容器内的端口,然后转发给它localhost:8000.

全部运行

现在你应该能够运行:

docker-compose -f path/to/your/compose-file.yaml up
Run Code Online (Sandbox Code Playgroud)

它将启动您的Apache服务器以及Sawtooth REST API和验证器以及您定义的任何其他服务.如果你去http://localhost:8000,你应该看到你的网页,如果你去http://localhost:8000/api/blocks,你应该看到链上的块的JSON表示.更重要的是,您应该能够从您的网络应用程序发出请求:

request.post({
    url: 'api/batches',
    body: batchListBytes,
    headers: { 'Content-Type': 'application/octet-stream' }
}, (err, response) => console.log(response) );
Run Code Online (Sandbox Code Playgroud)

.很抱歉很长的回复,但我不确定是否有可能更快地解决CORS.希望这会有所帮助.