Lync UCWA - 创建应用程序提供 HTTP 409:冲突错误

Posted

技术标签:

【中文标题】Lync UCWA - 创建应用程序提供 HTTP 409:冲突错误【英文标题】:Lync UCWA - Create application gives a HTTP 409: Conflict error 【发布时间】:2014-10-03 06:20:51 【问题描述】:

过去几天我一直在尝试使用 Microsoft 的 UCWA API(REST API)为我们的 Lync 服务开发应用程序。要使应用程序正常工作:我首先必须使用对某个 URL 的 POST 请求将其提交给 API。首先,我必须通过服务器进行身份验证,我通过向 API 发布用户名和密码凭据来做到这一点。然后我得到一个访问令牌,我可以通过在每个请求的标头中发布令牌来使用它来向 API 发出进一步的请求。我已经能够让访问令牌正常工作,但是当我尝试通过向 https://lyncextws.company.com/ucwa/oauth/v1/applications 发布 HTTP 请求来注册应用程序时:事情将开始出错。

所有这一切都是通过一个使用 iframe 绕过同源策略的 javascript 文件完成的。

这是我的代码目前的样子:

<!DOCTYPE html>
<html lang="no">
    <head>
        <meta charset="UTF-8" />
        <title>PresInfoDisp</title>
    </head>
    <body>
        <iframe src="https://lyncextws.company.com/Autodiscover/XFrame/XFrame.html" id="xFrame" style="display: none;"></iframe>
        <script type="text/javascript" src="jquery.js"></script>
        <script type="text/javascript">

        var access_token;

        var stage = 0;

        // CONNECT AND AUTHENTICATE WITH LYNC UCWA SERVICE
        function connectAndAuthenticate() 

            stage = 1;

            var request =  
              accepts: 'application/json', 
              type: 'POST', 
              url: 'https://lyncextws.company.com/WebTicket/oauthtoken',
              data: 'grant_type=password&username=alexander@domain.company.com&password=somePassword'
            ; 
            document.getElementById('xFrame').contentWindow.postMessage(JSON.stringify(request), 'https://lyncextws.company.com/WebTicket/oauthtoken');
        

        // REQUEST A USER RESOURCE
        function getUserResourceAuthRequest() 

            stage = 0;

            var request =  
              accepts: 'application/json', 
              type: 'GET', 
              url: 'https://lyncextws.company.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=company.com'
            ; 
            document.getElementById('xFrame').contentWindow.postMessage(JSON.stringify(request), 'https://lyncextws.company.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=company.com');

        

        function getUserResource() 

            stage = 2;

            var request =  
              accepts: 'application/json', 
              type: 'GET', 
              url: 'https://lyncextws.company.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=company.com',
              headers: Authorization: "Bearer "+access_token
            ; 
            document.getElementById('xFrame').contentWindow.postMessage(JSON.stringify(request), 'https://lyncextws.company.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=company.com');

        

        // REGISTER APPLICATION RESOURCE
        function registerApplication() 

            stage = 3;

            var request =  
              accepts: 'application/json', 
              type: 'POST', 
              url: 'https://lyncextws.company.com/ucwa/oauth/v1/applications',
              headers: Authorization: "Bearer "+access_token,
              data: 'userAgent': 'InfoDisp1',  'endpointId' : '2d9dc28d-4673-4035-825c-feb64be28e4e', 'culture': 'en-US'
            ; 
            document.getElementById('xFrame').contentWindow.postMessage(JSON.stringify(request), 'https://lyncextws.company.com/ucwa/oauth/v1/applications');

        

        // GRAB A LIST OF CONTACTS
        function listContacts() 

            stage = 4;

            var request =  
              accepts: 'application/json', 
              type: 'GET', 
              url: 'https://lyncextws.company.com/ucwa/oauth/v1/applications',
              headers: Authorization: "Bearer "+access_token
            ; 
            document.getElementById('xFrame').contentWindow.postMessage(JSON.stringify(request), 'https://lyncextws.company.com/ucwa/v1/applications');

        

        this.receiveMessage = function(message)  

            switch(stage) 
                case 1:

                    var beforeReplace = message.data.replace("/\\/g", "");
                    var json = jQuery.parseJSON(beforeReplace);
                    var json2 = jQuery.parseJSON(json.responseText);
                    access_token = json2.access_token;
                    console.log(json2.access_token);
                    console.log(message);

                    getUserResource();

                    break;
                case 0:
                    console.log(message);

                    connectAndAuthenticate();

                    break;

                case 2:

                    var beforeReplace = message.data.replace("/\\/g", "");
                    var json = jQuery.parseJSON(beforeReplace);
                    var json2 = jQuery.parseJSON(json.responseText);
                    console.log(json2._links.applications.href);

                    window.setTimeout(function()registerApplication(), 5000);

                    break;
                case 3:

                    console.log(message);

                    break;
                case 4:



                break;
            


        ; 
        window.addEventListener('message', this.receiveMessage, false);


        $(window).load(function() 
            getUserResourceAuthRequest();
            //console.log(access_token);
        );

        </script>
    </body>
</html>

当我运行此代码时:最后一个 ajax 查询返回错误 409:冲突,它应该返回 201:已创建

这是我的浏览器 (Google Chrome) 输出的内容:

401: Unauthorized 错误应该发生,但 409 冲突不应该发生。所以这是我的问题: 谁能发现为什么我得到这个 409 错误而不是我应该得到的 201?

Microsoft 的示例代码似乎运行良好,但我想避免使用它,因为我需要很长时间才能熟悉它。

如果缺少数据,您需要发现问题:在 cmets 中告诉我,我会提供!

【问题讨论】:

endpointId 总是那个静态字符串吗? @user1680977 是的。如果我从某个地方获得它?它会在哪里? 对于应用程序的 POST,您的请求标头/正文是什么样的?响应头/正文是什么样的? 【参考方案1】:

如果你替换

data: 'userAgent': 'InfoDisp1',  'endpointId' : '2d9dc28d-4673-4035-825c-feb64be28e4e', 'culture': 'en-US' 

用一串该数据代替 I.E.

data: "'userAgent': 'InfoDisp1',  'endpointId' : '2d9dc28d-4673-4035-825c-feb64be28e4e', 'culture': 'en-US'" 

似乎 data 需要一个字符串,在您的示例中,您正在向它传递一个 JSON 对象。这样做会使您的示例对我有用。

【讨论】:

哇...就是这么简单!谢谢! :)【参考方案2】:

问题似乎出在您的静态 endpointId 上。

在他们的原始帮助程序库中,他们有一个名为 generateUUID() 的方法,该方法位于 GeneralHelper 中。最好的想法是使用该方法,但是,如果您想创建自己的方法,那就去做吧。重点是你的每个应用程序必须有不同的endpointId。

【讨论】:

我已经尝试实现和使用该功能。它没有任何区别。还是一样的 409 错误。 嗯...我很确定就是这样。好吧,也许尝试使用辅助库?它们很有帮助 + 您不必自己编写所有内容 如果他使用静态端点,它会将响应代码(假设应用程序仍然有效)从 201(已创建)更改为 200(确定)。此时将返回原始应用程序。【参考方案3】:

您是否只是为了简洁而忽略了自动发现过程,还是真的在代码中跳过了自动发现并假设了发布“创建应用程序”的 URI?

对我来说,第二种情况似乎更多,这是不对的: 需要从用户资源请求的响应中检索创建应用程序的 URI(在您发布的代码中的 getUserResource 中)。 您在那里有一个名为 applications 的链接;它的值包含创建应用程序的正确 URI。

http://ucwa.lync.com/documentation/KeyTasks-CreateApplication

附:我在这里也发布了关于endpointId,看到我无法在上面发表评论 允许在不同的客户端使用同一个应用的endpointId。绝对不能假设在不同客户端上使用相同 endpointId 的应用程序会产生相同的基本应用程序资源 URI

【讨论】:

我尝试使用自动发现并从收到的响应中检索所有 URL。我阅读了有关创建应用程序的 UCWA 文档,并完全按照描述执行了步骤,但它仍然出现 409:冲突。我正在尝试阅读和理解 Microsoft 的示例代码,但对象模型有点过头了。如果我弄清楚了:我会发布答案。我会尽快将代码更新为我当前的代码。 这听起来更奇怪,还因为根据文档 409 并不是真正期望由此操作返回的状态代码。列出的唯一可能的返回码是 403 -> applications【参考方案4】:

我在使用 curl 来试验这个 API 时遇到了同样的问题,并且在同一时间失败了,直到我发现在这种情况下我需要将 content-type 标头设置为 json:

curl -v --data "'userAgent': 'test', 'endpointId': '54321', 'culture':'en-US', 'instanceID':'testinstance'" --header 'Content-Type: application/json' --header 'Authorization: Bearer cwt=AAEBHAEFAAAAAAA..' 'https://lyncserver.com/ucwa/oauth/v1/applications'

成功了!

【讨论】:

以上是关于Lync UCWA - 创建应用程序提供 HTTP 409:冲突错误的主要内容,如果未能解决你的问题,请参考以下文章

删除通过 UCWA 为过期应用程序安排的 Lync 2013 会议

使用 UCWA API 安排 Lync 会议

通过 ucwa lync 2013 发送消息

如何在 UCWA 1.0 API 中接受 Lync 对话邀请

Lync Ucwa 绕过 Lync 客户端

使用 node js 和 UCWA 的聊天应用程序