Node.js 如何在前端和后端位于不同端口时获得DocuSign嵌入式签名

Node.js 如何在前端和后端位于不同端口时获得DocuSign嵌入式签名,node.js,docusignapi,Node.js,Docusignapi,我正在进行一个项目,以集成DocuSign嵌入签名仪式功能。我的前端是Angular 6(端口:4200),它运行在与后端NodeJS(端口:3000)不同的端口上 前端将调用后端(RESTAPI)来生成PDF文件。完成后,它将触发重定向到embeddedsigning路由,以连接到DocuSign以获取PDF文件签名 成功生成PDF文件后,将触发'/api/docusign/signing'路由(请参阅下面的代码) 回调似乎不起作用,因为它将响应发送回前端,这不是我的意图。需要回调,以便将PD

我正在进行一个项目,以集成DocuSign嵌入签名仪式功能。我的前端是Angular 6(端口:4200),它运行在与后端NodeJS(端口:3000)不同的端口上

前端将调用后端(RESTAPI)来生成PDF文件。完成后,它将触发重定向到embeddedsigning路由,以连接到DocuSign以获取PDF文件签名

成功生成PDF文件后,将触发
'/api/docusign/signing'
路由(请参阅下面的代码)

回调似乎不起作用,因为它将响应发送回前端,这不是我的意图。需要回调,以便将PDF上载到DocuSign并触发DocuSign以提示签名者签名文档。完成后,后端将更新数据库,然后再传回前端

我仍然在学习和体验NodeJS,我不知道如何去做。任何有任何想法或经历的人都可以分享如何去做。谢谢你的帮助。谢谢

docusign routes.js

module.exports = (app) => {
    app.get('/api/docusign/auth', docuSignController.authenticate);
    app.get('/api/docusign/callback', [docuSignController.dsLoginCB1, docuSignController.dsLoginCB2]);
    app.get('/api/docusign/signing', docuSignController.requireDocuSignToken,
        docuSignController.embeddedsigning);
}
    exports.authenticate = (req, res, next) => {
        passport.authenticate('docusign')(req, res, next);
    };

    exports.requireDocuSignToken = (req, res, next) => {
        let tokenBufferMin = 30;
        let now = moment();

        console.log('requireDocuSignToken');

        if (tokenBufferMin && req.docusign && req.docusign.accessToken &&
            now.add(tokenBufferMin, 'm').isBefore(req.docusign.expires)) {
            console.log('\nUsing existing access token');
            next();
        } else {
            console.log('\nGet a new access token');
            res.redirect('http://localhost:3000/api/docusign/auth');
        }
   };

   exports.dsLoginCB1 = (req, res, next) => {
       passport.authenticate('docusign', {failureRedirect: '/api/docusign/auth'})(req, res, next);
   };

   exports.dsLoginCB2 = (req, res, next) => {
       res.redirect('/api/docusign/signing');
   }

   exports.embeddedsigning = (req, res, next) => {
    ...
   }
docuSignController.js

module.exports = (app) => {
    app.get('/api/docusign/auth', docuSignController.authenticate);
    app.get('/api/docusign/callback', [docuSignController.dsLoginCB1, docuSignController.dsLoginCB2]);
    app.get('/api/docusign/signing', docuSignController.requireDocuSignToken,
        docuSignController.embeddedsigning);
}
    exports.authenticate = (req, res, next) => {
        passport.authenticate('docusign')(req, res, next);
    };

    exports.requireDocuSignToken = (req, res, next) => {
        let tokenBufferMin = 30;
        let now = moment();

        console.log('requireDocuSignToken');

        if (tokenBufferMin && req.docusign && req.docusign.accessToken &&
            now.add(tokenBufferMin, 'm').isBefore(req.docusign.expires)) {
            console.log('\nUsing existing access token');
            next();
        } else {
            console.log('\nGet a new access token');
            res.redirect('http://localhost:3000/api/docusign/auth');
        }
   };

   exports.dsLoginCB1 = (req, res, next) => {
       passport.authenticate('docusign', {failureRedirect: '/api/docusign/auth'})(req, res, next);
   };

   exports.dsLoginCB2 = (req, res, next) => {
       res.redirect('/api/docusign/signing');
   }

   exports.embeddedsigning = (req, res, next) => {
    ...
   }

问题中显示的代码摘录没有显示
embeddedsigning
方法

该方法应该做什么:

  • 它已经知道它有一个好的docusignapi令牌
  • 它应该调用DocuSign方法。
    returnUrl
    参数可以是角度前端的URL,也可以是节点后端的URL。这取决于你的应用程序架构。两者都应该有效
  • 将用户浏览器重定向到DocuSign API调用响应中的
    url
    元素
  • 您可以在我编写的React/Redux示例中看到这方面的一个示例。在本例中,React应用程序直接调用DocuSign API(使用专用CORS网关)。参见文件第31-43行,重定向在第43行完成

    从Node.JS执行重定向,如下所示:

        res.redirect(results.url);
    
    下面是即将发布的代码示例中的一个示例:

    // Step 3. create the recipient view, the Signing Ceremony
    let viewRequest = makeRecipientViewRequest(envelopeArgs)
      , createRecipientViewP = req.dsAuthCodeGrant.makePromise(
            envelopesApi, 'createRecipientView')
      ;
    // call the CreateRecipientView API
    results = null; // reset
    try {
        results = await createRecipientViewP(accountId, envelopeId,
            {recipientViewRequest: viewRequest});
    } 
    catch (error) {
        let errorBody = error && error.response && error.response.body
            // we can pull the DocuSign error code and message from the response body
          , errorCode = errorBody && errorBody.errorCode
          , errorMessage = errorBody && errorBody.message
        res.render('pages/error', {err: error, errorCode: errorCode, errorMessage: errorMessage});
    }
    if (!results) {return}
    
    // Step 4. Redirect the user to the Signing Ceremony
    // Don't use an iFrame!
    // State can be stored/recovered using the framework's session or a
    // query parameter on the returnUrl (see the makeRecipientViewRequest method)
    res.redirect(results.url);
    
    以下是makeRecipientViewRequest 以下是makePromise代码:
    const{promisify}=require('util');
    //看http://2ality.com/2017/05/util-promisify.html
    /**
    *返回一个promise方法{methodName}\u promise,这是一个
    *方法参数的授权版本。
    *如果promise方法不存在,则创建它。
    *它通过父对象的附件进行缓存。
    *@函数
    *@param obj具有方法methodName的对象
    *@param methodName现有方法的字符串名称
    *@returns{promise}方法名的承诺版本。
    */
    DSAuthCodeGrant.prototype.makePromise=函数_makePromise(obj,methodName){
    让promiseName=methodName+'u promise';
    如果(!(obj中的承诺人姓名)){
    obj[promiseName]=promisify(obj[methodName]).bind(obj)
    }
    返回对象[承诺人姓名]
    }
    
    补充 (关于评论,请参见下文。)

    我认为您应该从后端使用passport。这样,passport/DocuSign重定向将转到您的后端

    由于您试图从前端做太多工作,所以您遇到了CORS问题

    如果你想编写更多的纯前端DocuSign应用程序,你可以,但你需要一个私人CORS网关。查看我的博客帖子,然后


    注意:对于前端应用程序,您必须使用隐式授权,而不是授权码授权。

    感谢您的回复。问题是passport.authenticate使用此URL重定向到我的前端localhost:4200。。。当浏览器控制台指示错误时,飞行前的响应无效(重定向)。它无法访问/api/docusign/callback。当我使用postman测试时,嵌入的签名功能正在工作。@user10153962,我已添加到我答案的底部。欢迎使用StackOverflow!请投票选出所有有用的答案,包括对他人问题的答案。请检查/接受您自己问题的最佳答案!
    const {promisify} = require('util'); 
    // See http://2ality.com/2017/05/util-promisify.html
    
    /**
     * Returns a promise method, {methodName}_promise, that is a
     * promisfied version of the method parameter.
     * The promise method is created if it doesn't already exist.
     * It is cached via attachment to the parent object.
     * @function
     * @param obj An object that has method methodName
     * @param methodName The string name of the existing method
     * @returns {promise} a promise version of the <tt>methodName</tt>.
     */
    DSAuthCodeGrant.prototype.makePromise = function _makePromise(obj, methodName){
      let promiseName = methodName + '_promise';
      if (!(promiseName in obj)) {
        obj[promiseName] = promisify(obj[methodName]).bind(obj)
      }
      return obj[promiseName]
    }