【问题标题】:SOAP server with Express.js带有 Express.js 的 SOAP 服务器
【发布时间】:2023-03-27 06:25:01
【问题描述】:

我使用node-soap 创建了一个简单的 SOAP 服务器,它当前正在为来自 SOAP 客户端的请求提供服务。现在的要求是为将来来自不同客户端的传入 REST 和 SOAP 请求提供服务。我的问题是我可以通过使用单个 Express 应用程序(使用 Express.js 框架)来实现这一点吗?我是新手,所以任何帮助将不胜感激。提前致谢!

【问题讨论】:

    标签: node.js web-services express soap


    【解决方案1】:

    我认为prasun 已经给出了很好的例子,但想更详细地分享我的例子。 我使用了expresssoap,但是使用http / https 来创建服务器而不是使用express

    首先,下面是项目结构,我模块化了 RESTful 端点路由器的路由文件夹和 Soap WebService 端点的服务文件夹

    /config/index.js    
    /routes/index.js
    /services/wsdl/poservice.wsdl
    /services/poservice.js
    app.js
    server.js
    

    通过 express 创建路由器并为根 ('/') 上下文路径的 GET 请求构建端点

    [路由器/index.js]

    var express = require('express');
    var router = express.Router();
    
    router.get('/', function(req, res, next) {
      res.setHeader('Content-Type', 'application/json');
      res.send(JSON.stringify({"data": "some data"}));
    });
    
    module.exports = router;
    

    在 app.js 上构建主路由图

    [app.js]

    var express = require('express');
    var bodyParser = require('body-parser');
    var indexRouter = require('./routes/index');
    
    var app = express();
    app.use(bodyParser.raw({type: function(){return true;}, limit: '5mb'}));
    
    app.use('/', indexRouter);
    module.exports = app;
    

    设置服务、端口和操作对象,并从文件路径 (./services/wsdl/PurchaseOrderServiceV2.wsdl) 发布 wsdl

    [服务/poservice.js]

    var fs = require('fs');
    var path = require('path');
    var poServiceXml = fs.readFileSync(path.join(path.join(__dirname, 'wsdl'), 'PurchaseOrderServiceV2.wsdl'), 'utf8');
    
    var poService = {
      PurchaseOrderService: {
          PurchaseOrderServiceSoapHttpPort: {
              getPurchaseOrder: function(args) {
                  console.log(args);
                  return {
                      name: args.name
                  };
              }
          }
       }
    };
    
    module.exports = {
      service: poService,
      xml: poServiceXml
    };
    

    此服务、端口和操作设置基于 wsdl。下面是截断的wsdl服务、端口和操作定义

    [服务/wsdl/PurchaseOrderServiceV2.wsdl]

    <wsdl:operation name="getPurchaseOrder">
      <wsdl:input message="tns:PurchaseOrderService_getPurchaseOrder"/>
      <wsdl:output message="tns:PurchaseOrderService_getPurchaseOrderResponse"/>
      <wsdl:fault name="ServiceException" message="errors:ServiceException"/>
    </wsdl:operation>
                 :
    
    <wsdl:service name="PurchaseOrderService">
      <wsdl:port name="PurchaseOrderServiceSoapHttpPort" binding="tns:PurchaseOrderServiceSoapHttp">
        <soap:address location="https://efqf-test.prc.us6.oraclecloud.com:443/prcPoEditDocumentOrder/PurchaseOrderServiceV2"/>
                 :
    

    现在创建服务器并运行 RESTful 和 Soap 端点

    [server.js]

    var fs = require('fs');
    var config = require('./config');
    var app = require('./app');
    var debug = require('debug')('po-service:server');
    var http = require('http');
    var https = require('https');
    var soap = require('soap');
    const poService = require('./services/poservice');
    
    /**
     * Get port from environment and store in Express.
     */
    
    var port = normalizePort(process.env.PORT || config.get('app.port'));
    app.set('port', port);
    
    /**
     * Create HTTP server or HTTPS server
     */
    var server = http.createServer(app);
    if(config.get('app.https')) {
      server = https.createServer({
        key: fs.readFileSync(config.get('app.serverkey')),
        cert: fs.readFileSync(config.get('app.servercert'))
      }, app);
    }
    
    /**
     * Listen on provided port, on all network interfaces.
     */
    function startServer() {
      server.listen(port);
      server.on('error', onError);
      server.on('listening', onListening);
      soap.listen(server, '/prcPoEditDocumentOrder/PurchaseOrderServiceV2', poService.service, poService.xml);
    }
    
    if(!module.parent) {
      // Start server if file is run directly
      startServer();
    } else {
      // Export server, if file is referenced via cluster
      module.exports = startServer;
    }
    
    /**
     * Normalize a port into a number, string, or false.
     */
    function normalizePort(val) {
      var port = parseInt(val, 10);
    
      if (isNaN(port)) {
        // named pipe
        return val;
      }
      if (port >= 0) {
        // port number
        return port;
      }
      return false;
    }
    
    /**
     * Event listener for HTTP server "error" event.
     */
    
    function onError(error) {
      if (error.syscall !== 'listen') {
        throw error;
      }
    
      var bind = typeof port === 'string'
      ? 'Pipe ' + port
      : 'Port ' + port;
    
      // handle specific listen errors with friendly messages
      switch (error.code) {
        case 'EACCES':
          console.error(bind + ' requires elevated privileges');
          process.exit(1);
          break;
        case 'EADDRINUSE':
          console.error(bind + ' is already in use');
          process.exit(1);
          break;
        default:
          throw error;
      }
    }
    
    /**
     * Event listener for HTTP server "listening" event.
     */
    
    function onListening() {
      var addr = server.address();
      var bind = typeof addr === 'string'
          ? 'pipe ' + addr
          : 'port ' + addr.port;
      debug('Listening on ' + bind);
    }
    

    对于配置,我有配置模块

    [配置/index.js]

    var PropertiesReader = require('properties-reader');
    var config = new PropertiesReader('app.properties');
    
    module.exports = config;
    

    下面是配置文件

    [app.properties]

    [app]
    hostname = localhost
    port = 8080
    https = false
    serverkey = /path/to/signed.key
    servercert = /path/to/signed.crt
    

    现在验证 RESTful 端点

    $ curl http://localhost:8080/
    {"data":"some data"}
    

    通过高级 REST 客户端验证 Soap 端点

    或通过 SoapUI

    检查发布的wsdl可以被浏览器检索

    【讨论】:

    • 我非常喜欢这个答案。但是您能否向我解释一下:
      efqf-test.prc.us6.oraclecloud.com:443/prcPoEditDocumentOrder/…> 标签。查看soap 文档,它说“SOAP 1.2 地址可扩展性元素指定用于连接到SOAP 服务器的URL 地址。”应该怎么做?这个例子中的 URL 是什么?我得到的错误是 Error: Failed to bind to WSDL
    • 我作为示例使用的 PurchaseOrderServiceV2 API 是 Oracle Cloud ERP API,原始截断的 WSDL(我分享的不是完整的 WSDL)正在显示测试环境。但是上面的例子是从本地文件路径加载 complete WSDLpoService.xml 并通过soap.listen(server, '/prcPoEditDocumentOrder/PurchaseOrderServiceV2'... 设置本地端点的情况,因此它不需要连接到原始 WSDL 发布的 URL 或原始服务端点,只要在您的文件路径中有完整的 WSDL。
    • 我试图给出一个如何设置的想法,但如果你真的想让上面的代码在你的环境中工作,你可以从efqf-test.prc.us6.oraclecloud.com/fscmService/… 下载完整的 PurchaseOrderServiceV2.wsdl 或分享你的项目,所以我可以帮忙
    • 感谢您的信息。我现在已经设法让它工作了。从 .xsd 文件中导入类型对我来说仍然是个问题。但是将它放在同一个文件中它可以正常工作。 :)
    【解决方案2】:

    pull#872 开始,它支持开箱即用的express 服务器。

    expressServer = express();
    server = expressServer.listen(51515, function(){
          var soapServer = soap.listen(expressServer, '/SayHello', service, wsdl);
    });
    

    其中\sayHello 是您要处理wsdl 请求的路由。

    另外,请注意,它还将支持所有中间件和正文解析器。

    有关语法的更多详细信息,您可以查看此拉取请求中包含的测试。

    【讨论】:

      【解决方案3】:

      像往常一样编写您的 express 应用程序

      var soap = require('soap');
      var express = require('express');
      
      var app = express();
      
      app.use('/', express.static(__dirname + '/public'));
      app.use('/node_modules', express.static(__dirname + '/node_modules'));
      
      /* other express part */
      

      但不要这样做 app.listen

      像这样构建你的服务器

      var server = require('http').createServer(app);
      

      代码soap部分并像这样终止

      soap.listen(server, '/wsdl', MyService, xml);
      server.listen(8080);
      

      如果你也想使用 websocket 也可以使用服务器

      var io = require('socket.io')(server);
      /* io part */
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-18
        • 2021-08-03
        • 1970-01-01
        • 2021-04-04
        • 1970-01-01
        • 2021-10-10
        • 1970-01-01
        • 2015-03-10
        相关资源
        最近更新 更多