SharePoint表单跨域调用外部服务遇Access Denied及CORS配置问题
我来帮你搞定这个跨域报错的问题!你遇到的XMLHttpRequest: Network Error 0x80070005, Access is denied.是标准的跨域资源共享(CORS)限制,而且你之前踩了个常见坑——Access-Control-Allow-Origin是要在服务器端配置的响应头,不是写在前端AJAX请求里的,浏览器当然识别不了啦。
先给你梳理下原代码里的两个小问题:
- 数据格式错误:你写的
data参数"userName:"+username+",date:"+today()+",modified_by:"+username+"}"既不是合法的JSON,也不符合XML请求格式,还多了个多余的},这肯定会导致服务端解析失败。 - CORS配置位置错误:前端请求里加
Access-Control-Allow-Origin完全没用,这个头必须由你调用的HRMServices.asmx服务返回给浏览器,浏览器才会允许跨域请求。
第一步:修正服务端的CORS配置(核心解决步骤)
因为你调用的是ASMX服务,有两种方式配置CORS:
方式1:在单个WebMethod中添加响应头
打开ASMX对应的.cs代码文件,在GetEmployeeInfo方法里添加响应头:
[WebMethod] public EmployeeInfo GetEmployeeInfo(string userName, string date, string modified_by) { // 先添加CORS允许头 HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); // 这里写你的服务端业务逻辑,比如查询员工信息 // ... return employeeInfo; }
方式2:全局配置(推荐)
如果这个服务要被多个前端调用,直接在服务端的web.config里添加全局CORS配置:
<system.webServer> <httpProtocol> <customHeaders> <!-- 允许所有域跨域请求,也可以指定具体域名比如https://your-sharepoint-site.com --> <add name="Access-Control-Allow-Origin" value="*" /> <!-- 允许的请求方法 --> <add name="Access-Control-Allow-Methods" value="POST, GET, OPTIONS" /> <!-- 允许的请求头 --> <add name="Access-Control-Allow-Headers" value="Content-Type" /> </customHeaders> </httpProtocol> </system.webServer>
⚠️ 注意:如果你的SharePoint站点是HTTPS,而ASMX服务是HTTP,浏览器会因为「混合内容」阻止请求,最好把服务端也改成HTTPS。
第二步:修正前端AJAX代码
根据服务端支持的格式,推荐用JSON格式(比XML更简洁),以下是修正后的代码:
function CallClientIDWebSerivce() { var URL = "http://applicationsrv/HRMServices.asmx/GetEmployeeInfo"; // 这里替换成从SharePoint获取当前用户名的逻辑,比如_spPageContextInfo.userLoginName var username = _spPageContextInfo.userLoginName; // 生成符合服务端要求的日期格式,示例为YYYY-MM-DD var today = new Date().toISOString().split('T')[0]; $.ajax({ type: "POST", url: URL, dataType: "json", // 用JSON.stringify把参数转成合法的JSON字符串 data: JSON.stringify({ userName: username, date: today, modified_by: username }), contentType: "application/json; charset=utf-8", success: function (response) { // ASMX服务返回的结果通常包裹在d属性里 console.log("获取到的员工信息:", response.d); alert(JSON.stringify(response.d)); }, error: function (jqXHR, textStatus, errorThrown) { console.error("请求失败详情:", textStatus, errorThrown); alert('请求失败,请检查服务配置或联系管理员'); } }); }
如果服务端必须用XML格式,那data要写成符合SOAP规范的XML结构,比如:
data: '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetEmployeeInfo xmlns="http://tempuri.org/"><userName>' + username + '</userName><date>' + today + '</date><modified_by>' + username + '</modified_by></GetEmployeeInfo></soap:Body></soap:Envelope>', contentType: "text/xml; charset=utf-8",
备选方案:用SharePoint自带的SP.RequestExecutor
如果不想配置服务端CORS,也可以用SharePoint提供的SP.RequestExecutor来发起跨域请求,这是SharePoint专门为跨域场景设计的工具:
function CallClientIDWebSerivce() { var serviceUrl = "http://applicationsrv/HRMServices.asmx/GetEmployeeInfo"; // 替换成你的SharePoint站点URL var spSiteUrl = _spPageContextInfo.webAbsoluteUrl; var executor = new SP.RequestExecutor(spSiteUrl); var username = _spPageContextInfo.userLoginName; var today = new Date().toISOString().split('T')[0]; executor.executeAsync({ url: serviceUrl, method: "POST", contentType: "application/json; charset=utf-8", body: JSON.stringify({ userName: username, date: today, modified_by: username }), success: function(response) { var employeeData = JSON.parse(response.body).d; console.log("员工信息:", employeeData); }, error: function(error) { console.error("请求失败:", error); } }); }
最后给你个调试小技巧:打开浏览器开发者工具的「Network」标签,查看请求的响应头,如果能看到Access-Control-Allow-Origin,说明服务端配置生效了;如果还是报错,检查请求方法、内容类型是否和服务端要求一致。
内容的提问来源于stack exchange,提问作者Hoorie

