Fixing issue in making cross domain Ajax call to SharePoint REST service in Chrome
This post is a contribution from Jing Wang, an engineer with the SharePoint Developer Support team
Symptom:
Remote Ajax Application is configured with Windows Authentication. It makes XMLHttpRequest to SharePoint 2013 Web Service, listdata.svc.
Sample code:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js" type="text/javascript" ></script>
<script src="https://code.jquery.com/jquery-1.9.1.js" type="text/javascript" ></script>
</head>
<body>
<h1>test page</h1>
<script type="text/javascript">
//Ajax call to use listdata.svc
var restUrl = "https://SharePointSiteUrl/_vti_bin/listdata.svc/List1";
$.ajax({
url: restUrl,
type: "GET",
dataType: 'JSON',
headers: {
"Content-Type": "'application/json;odata=verbose'",
"Accept": "application/json;odata=verbose",
"crossDomain": "true",
"credentials":"include"
},
xhrFields: { withCredentials: true },
success: function(response) {
alert("Success");
},
error: function(response){
alert("Error" );
}
});
</script>
</body>
</html>
When use Chrome to browse to the above page, you will see the below error
Failed to load resource: the server responded with a status of 401 dev.contoso.com/_vti_bin/listdata.svc/EMSPropertyLibrary()?$filter......
(Unauthorized)
Below is screen shot of error in Browser Developer tool console window :
Cause:
The XMLHttpRequest was sent with added custom headers, like,
headers.append('Content-Type', 'application/json;odata=verbose');
headers.append('credentials', 'include');
These custom headers made the request NOT a "Simple Request", see reference, https://developer.mozilla.org/en-US/docs/Web/HTTP/Access\_control\_CORS
Since the request here with header ('Content-Type', 'application/json;odata=verbose'), it is not a Simple Request and the following process will happen.
- Browser (Chrome) sent preflight OPTIONS request to SharePoint WFE server, which hosts the listdata.svc, without credential first,
- Server returned HTTP/1.1 401 Unauthorized response for the preflight request.
- Due to 401 Unauthorized response from server the actual Web Service request will get dropped automatically.
Fiddler trace shows:
Solution:
Step I,
Force SharePoint WFE Server to send Http Status code of 200 for the preflight requests by us IIS’s new URL Rewrite tool:
- Install "web platform installer" from https://www.microsoft.com/web/downloads/platform.aspx
- Go to "Applications" tab and search for "URL Rewrite" and download it
- Open IIS configuration tool (inetmgr) and select the root node having the machine name in the IIS. Double click "URL Rewrite" in the features view on the right hand side.
- Add a new blankrule by clicking on Add Rule --> New Blank Rule from the menu on the right
- Give it any name
- In "Match URL", specify this pattern: .*
- In "Conditions" click on Add and specify this condition entry: {REQUEST_METHOD} and this pattern: ^OPTIONS$
- In "Action", specify: action type Personalized response (or Customized reponse), state code 200, reason Preflight, description Preflight
- Click on Apply
Now, the server should reply with a 200 status code response to the preflight request, regardless of the authentication.
Step II,
Since this is a CORS request, above change is not enough to make the XMLHttpRequest call go through.
With the changes in Step I, Chrome Browser console shows a different error:
(index):1 XMLHttpRequest cannot load https://***/_vti_bin/listdata.svc...
Request header field crossDomain is not allowed by Access-Control-Allow-Headers in preflight response.
Make the following changes to the web.config for the SharePoint Web Application, to allow more custom headers required to enable CORS:
Sample code block in Web.Config. You will need to update the value of Access-Control-Allow-Origin to point to your remote ajax application.
----
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="https://AngularjsSiteUrl" />
<add name="Access-Control-Allow-Headers" value="Content-Type,Accept,X-FORMS_BASED_AUTH_ACCEPTED,crossDomain,credentials " />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
The above changes will help to fix the issue and the Ajax request will now execute successfully.
Comments
- Anonymous
July 07, 2017
I know this website offers quality based articles and additional material, is there any other web page which presents such data in quality? - Anonymous
November 08, 2017
Thanks, awesome ))