Javascript从Dynamics Online发布到外部网站

[英]Javascript post to external site from Dynamics Online


I've been trying for most of the day to post data to an external WebAPI endpoint when the OnSave event is triggered from a Microsoft Dynamics 365 form. Unfortunately, despite an extraordinary amount of research, I haven't been able to successfully post the data.

当从Microsoft Dynamics 365表单触发OnSave事件时,我一直在尝试将数据发布到外部WebAPI端点。不幸的是,尽管进行了大量研究,但我还是无法成功发布数据。

Having spent about an hour stumbling around getting the javascript library referenced in the right form, I tried reference jQuery from within my script, and trying to use $.ajax to trigger the post, using a declared alias. Here's a redacted version of the code:

花了大约一个小时磕磕绊绊地想要以正确的形式引用javascript库,我尝试从我的脚本中引用jQuery,并尝试使用$ .ajax来触发帖子,使用声明的别名。这是代码的编辑版本:

function UpdateSupplierStatus()
{
   var $jQ = jQuery.noConflict();

   var MembershipNumber = 
Xrm.Page.data.entity.attributes.get("membershipnumber").getValue();
var StatusCode = Xrm.Page.data.entity.attributes.get("statuscode").getText();

$jQ.ajax({
    url: 'http://myurl.com/api/MembershipAPI/UpdateMembershipStatus', 
    type: 'POST',
    data: {
            'membershipNumber' : MembershipNumber,
            'statusCode' : StatusCode
        },
    datatype: 'json',
    success: function() {},
    error: alert("There was an error performing the update.")
});
}

No matter what I try, it seems that as soon as I try to execute the post, I fall straight into the 'error' clause. I've run Fiddler in the background whilst debugging the script using Internet Explorer, and there's no attempt made to hit the endpoint specified - it simply doesn't try, just errors.

无论我尝试什么,似乎只要我尝试执行帖子,我就会直接进入“错误”条款。我在后台运行Fiddler,同时使用Internet Explorer调试脚本,并且没有尝试命中指定的端点 - 它只是不尝试,只是错误。

I did some research, and came across a number of articles like this that suggest using XmlHttpRequest instead of trying to poke posts around the internet using jQuery, and so I tried using this instead:

我做了一些研究,并且发现了许多像这样的文章建议使用XmlHttpRequest而不是试图使用jQuery在互联网上发帖,所以我尝试使用它:

function UpdateSupplierStatus()
{
var MembershipNumber = Xrm.Page.data.entity.attributes.get("membershipnumber").getValue();
var StatusCode = Xrm.Page.data.entity.attributes.get("statuscode").getText();

var Query = "?membershipNumber=" + MembershipNumber + "&statusCode=" + StatusCode;
var URL = "http://myurl.com/api/MembershipAPI/UpdateMembershipStatus";

var req = new XMLHttpRequest();
req.open("POST", URL + Query, true);
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");

req.send(JSON.stringify(data));
}

Again, if I debug this it's unsuccessful, however this time it seems that the offending line is 'req.open(...' - from what I've read, the suggestion is that I can't use XmlHttpRequest to make requests to resources outside of the hosts domain. The problem here is that CRM is hosted and the related website is obviously elsewhere. There is a question around this problem that describes the 'fix' as requiring users to alter their security settings, but frankly I find this to be madness - I cannot, and will not, require my customers to alter their security settings to allow this to work.

再次,如果我调试它不成功,但这次似乎违规行是'req.open(...' - 从我读过的,我的建议是我不能使用XmlHttpRequest来发出请求主机域之外的资源。这里的问题是CRM托管,相关网站显然是其他地方。有一个问题围绕这个问题描述'修复'要求用户改变他们的安全设置,但坦率地说,我发现这个疯狂 - 我不能,也不会,要求我的客户改变他们的安全设置以使其工作。

What am I missing here? Is it really this difficult to post data to an external site using Dynamics 365, or is there some process that I'm missing that facilitates exactly this?

我在这里想念的是什么?使用Dynamics 365将数据发布到外部站点真的很难吗,或者是否有一些我缺少的过程正是如此?

Edit So I've tried testing this with a different browser and I get further using the XmlHttpRequest method than I was getting with the $.ajax method. However, I've not self-signed localhost, and our staging environment has no SSL certificate, and so I can't supply the content via HTTPS. I now have two issues:

编辑所以我尝试使用不同的浏览器进行测试,然后我使用XmlHttpRequest方法进一步使用$ .ajax方法。但是,我没有自签名localhost,我们的暂存环境没有SSL证书,因此我无法通过HTTPS提供内容。我现在有两个问题:

I can't require people to not use IE
I can't easily get HTTPS working in either my development environment, or in my staging environment

I'm starting to feel more and more like this isn't a problem with Dynamics!

我不能要求人们不使用IE我不能轻易地让HTTPS在我的开发环境中工作,或者在我的暂存环境中我开始感觉越来越多,这对于Dynamics来说不是问题!

2 个解决方案

#1


4  

This is not an issue related to Dynamics 365 but related to CORS:

这不是与Dynamics 365相关但与CORS相关的问题:

For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts. For example, XMLHttpRequest and Fetch follow the same-origin policy. So, a web application using XMLHttpRequest or Fetch could only make HTTP requests to its own domain.

出于安全原因,浏览器会限制从脚本中发起的跨源HTTP请求。例如,XMLHttpRequest和Fetch遵循同源策略。因此,使用XMLHttpRequest或Fetch的Web应用程序只能向其自己的域发出HTTP请求。

The Cross-Origin Resource Sharing (CORS) mechanism gives web servers cross-domain access controls, which enable secure cross-domain data transfers. Modern browsers use CORS in an API container - such as XMLHttpRequest or Fetch - to mitigate risks of cross-origin HTTP requests.

跨源资源共享(CORS)机制为Web服务器提供跨域访问控制,从而实现安全的跨域数据传输。现代浏览器在API容器中使用CORS(例如XMLHttpRequest或Fetch)来降低跨源HTTP请求的风险。

More information...

更多信息...

You will find a lot of examples about different scenarios and different ways to perform a cross-domain request (in the previous link you will find a lot of these information).

您将找到许多关于不同场景和执行跨域请求的不同方法的示例(在上一个链接中,您将找到大量这些信息)。

The following it's a "simple request", which I think it will work in your scenario (the allowed methods are GET, HEAD and POST), and you can test it directly from CRM if you want (I've done it without problems as you can see in the screenshot that I've also uploaded):

以下是一个“简单请求”,我认为它可以在你的场景中工作(允许的方法是GET,HEAD和POST),如果你愿意,你可以直接从CRM测试它(我已经完成了它没有问题)你可以在截图中看到我也上传了):

function callOtherDomain() {
  var req = new XMLHttpRequest();
  var url = 'https://httpbin.org/get';

  req.open('GET', url, true);

  req.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
       alert(req.responseText);
    }
  };

  req.send(); 
}

enter image description here

This "simple request" will use CORS headers to handle the privileges:

这个“简单请求”将使用CORS头来处理权限:

enter image description here

As you can see, the server (http://myurl.com in your scenario) also has to be configured to explicitly allow cross-domain requests. You can see a very detailed tutorial to enable this option in the following MSDN article (assuming that you're using WebAPI).

如您所见,服务器(您的方案中的http://myurl.com)也必须配置为明确允许跨域请求。您可以在以下MSDN文章中看到一个非常详细的教程来启用此选项(假设您使用的是WebAPI)。

#2


0  

Your jQuery ajax call is not working because you are not passing a function definition to your error handler, but rather executing some code (alert...) directly.

您的jQuery ajax调用无法正常工作,因为您没有将函数定义传递给错误处理程序,而是直接执行某些代码(alert ...)。

Try wrapping the code in an inline function definition like this:

尝试将代码包装在内联函数定义中,如下所示:

$jQ.ajax({
 url: 'http://myurl.com/api/MembershipAPI/UpdateMembershipStatus', 
 type: 'POST',
 data: {
        'membershipNumber' : MembershipNumber,
        'statusCode' : StatusCode
    },
 datatype: 'json',
 success: function() {},
 error: function() { alert("There was an error performing the update."); }
});

Also, add this line in the beginning of your code (after the .noConflict):

另外,在代码的开头添加此行(在.noConflict之后):

$jQ.support.cors = true;

Furthermore, please make sure your webservice accepts Cross Origin Requests.To do so in your Web API project, make the following changes:

此外,请确保您的Web服务接受Cross Origin Requests。要在Web API项目中执行此操作,请进行以下更改:

  • Install the Nuget Package Microsoft.AspNet.WebApi.Cors
  • 安装Nuget包Microsoft.AspNet.WebApi.Cors
  • Add the following attribute to your class:

    将以下属性添加到您的类:

    [EnableCors(origins: "*", headers: "*", methods: "*", exposedHeaders: "")] public class MembershipAPIController : ApiController

    [EnableCors(起源:“*”,标题:“*”,方法:“*”,exposedHeaders:“”)]公共类MembershipAPIController:ApiController

  • Add the following in your web.config under the tag:

    在标记下的web.config中添加以下内容:

    <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Methods" value="*" /> </customHeaders> <httpProtocol>

The last step is needed to include both headers in the response. When these headers are missing, the response will be blocked by the browser. I'm pretty sure you're missing the xml-tags in your web.config.

最后一步是在响应中包含两个标头。如果缺少这些标头,浏览器将阻止响应。我很确定你错过了web.config中的xml-tags。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2017/04/11/a827a695c8143417a690088ac0125069.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com