在构建 SharePoint 外接程序时,您通常必须包含来自各个源的数据。 出于安全原因,我们制定了防止跨域通信的阻止机制。 当您使用 Web 代理时,您的外接程序中的网页可访问远程域和 SharePoint 域中的数据。
作为开发者,可以使用在客户端 API 中公开的 Web 代理,如 JavaScript 和 .NET 客户端对象模型。 使用 Web 代理时,将向 SharePoint 发出初始请求。 反过来,SharePoint 向指定终结点请求数据,并将该请求转发回你的页面。
如果你希望通信出现在服务器级别,请使用 Web 代理。 有关详细信息,请参阅
SharePoint 加载项的安全数据访问和客户端对象模型
。
SharePoint Web 代理是代码和外部数据源之间的中间人
使用本文中的示例的先决条件
若要按照此示例中的步骤操作,则需要:
Visual Studio 2015 和最新的 Microsoft Office 开发人员工具
SharePoint 开发环境(本地方案需要外接程序隔离)
使用 Web 代理前要了解的核心概念
下表列出了一些有用的文章,可帮助你了解 SharePoint 加载项的跨域方案中涉及的概念。
SharePoint 外接程序的安全数据访问和客户端对象模型
了解 SharePoint 外接程序中的数据访问选项。本文提供了有关在使用外接程序中的数据时必须从中进行选择的高级别备用项的指南。
SharePoint 中的主机 Web、外接程序 Web 和 SharePoint 组件
了解主机 Web 和外接程序 Web 之间的区别。 了解 SharePoint 外接程序中可以包括哪些 SharePoint 组件、将哪些组件部署到主机 Web、将哪些组件部署到外接程序 Web 以及如何将外接程序 Web 部署到隔离域中。
客户端跨域安全性
了解跨域威胁和用例以及跨源请求的安全准则,并权衡开发人员增强从在浏览器中运行的 Web 应用程序进行的跨域访问的风险。
使用
SharePoint 加载项
模板创建新的项目。
下图显示了“SharePoint 加载项”
模板在 2015 中的位置,具体位于“模板”
>“Visual C#”
>“Office/SharePoint”
>“Office 加载项”
下。
SharePoint 加载项 Visual Studio 模板
提供要用于调试的 SharePoint 网站的 URL。
选择"Sharepoint 托管"作为您的外接程序的托管选项。
使用 JavaScript 对象模型修改 Default.aspx 页以使用 Web 代理
双击"页面"文件夹中的"Default.aspx"页。
复制以下标记并将其粘贴到页面的
PlaceHolderMain
内容标记中。 该标记将执行以下任务:
为远程数据提供占位符。
引用 SharePoint JavaScript 文件。
准备包含
WebRequestInfo
对象的请求。
准备请求
Accept
标头来以 JavaScript 对象表示法 (JSON) 格式指定响应。
发出对远程终结点的调用。
处理成功完成的操作,并在 SharePoint 网页中呈现远程数据。
处理任何错误,并在 SharePoint 网页中呈现错误消息。
Categories from the Northwind database exposed as an OData service:
<!-- Placeholder for the remote content -->
<span id="categories"></span>
<!-- Add references to the JavaScript libraries. -->
<script
type="text/javascript"
src="../_layouts/15/SP.Runtime.js">
</script>
<script
type="text/javascript"
src="../_layouts/15/SP.js">
</script>
<script type="text/javascript">
(function () {
"use strict";
// Prepare the request to an OData source
// using the GET verb.
var context = SP.ClientContext.get_current();
var request = new SP.WebRequestInfo();
request.set_url(
"http://services.odata.org/Northwind/Northwind.svc/Categories"
request.set_method("GET");
// We need the response formatted as JSON.
request.set_headers({ "Accept": "application/json;odata=verbose" });
var response = SP.WebProxy.invoke(context, request);
// Let users know that there is some
// processing going on.
document.getElementById("categories").innerHTML =
"<P>Loading categories...</P>";
// Set the event handlers and invoke the request.
context.executeQueryAsync(successHandler, errorHandler);
// Event handler for the success event.
// Get the totalResults node in the response.
// Render the value in the placeholder.
function successHandler() {
// Check for status code == 200
// Some other status codes, such as 302 redirect
// do not trigger the errorHandler.
if (response.get_statusCode() == 200) {
var categories;
var output;
// Load the OData source from the response.
categories = JSON.parse(response.get_body());
// Extract the CategoryName and Description
// from each result in the response.
// Build the output as a list.
output = "<UL>";
for (var i = 0; i < categories.d.results.length; i++) {
var categoryName;
var description;
categoryName = categories.d.results[i].CategoryName;
description = categories.d.results[i].Description;
output += "<LI>" + categoryName + ":&nbsp;" +
description + "</LI>";
output += "</UL>";
document.getElementById("categories").innerHTML = output;
else {
var errordesc;
errordesc = "<P>Status code: " +
response.get_statusCode() + "<br/>";
errordesc += response.get_body();
document.getElementById("categories").innerHTML = errordesc;
// Event handler for the error event.
// Render the response body in the placeholder.
// The body includes the error message.
function errorHandler() {
document.getElementById("categories").innerHTML =
response.get_body();
})();
</script>
准备请求 SP.WebRequest.Invoke 终结点。
使用 SP.WebrequestInfo 对象准备请求的正文。 该对象包括用于以 JavaScript 对象表示法 (JSON) 格式指定响应的 Accept 标头。
发出对远程终结点的调用。
处理成功完成的操作,并在 SharePoint 网页中呈现远程数据。
处理任何错误,并在 SharePoint 网页中呈现错误消息。
Categories from the Northwind database exposed as an OData service:
<!-- Placeholder for the remote content -->
<span id="categories"></span>
<script
type="text/javascript"
src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.min.js">
</script>
<script type="text/javascript">
(function () {
"use strict";
// The Northwind categories endpoint.
var url =
"http://services.odata.org/Northwind/Northwind.svc/Categories";
// Let users know that there is some
// processing going on.
document.getElementById("categories").innerHTML =
"<P>Loading categories...</P>";
// Issue a POST request to the SP.WebProxy.Invoke endpoint.
// The body has the information to issue a GET request
// to the Northwind service.
$.ajax({
url: "../_api/SP.WebProxy.invoke",
type: "POST",
data: JSON.stringify(
"requestInfo": {
"__metadata": { "type": "SP.WebRequestInfo" },
"Url": url,
"Method": "GET",
"Headers": {
"results": [{
"__metadata": { "type": "SP.KeyValue" },
"Key": "Accept",
"Value": "application/json;odata=verbose",
"ValueType": "Edm.String"
headers: {
"Accept": "application/json;odata=verbose",
"Content-Type": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
success: successHandler,
error: errorHandler
// Event handler for the success event.
// Get the totalResults node in the response.
// Render the value in the placeholder.
function successHandler(data) {
// Check for status code == 200
// Some other status codes, such as 302 redirect,
// do not trigger the errorHandler.
if (data.d.Invoke.StatusCode == 200) {
var categories;
var output;
// Load the OData source from the response.
categories = JSON.parse(data.d.Invoke.Body);
// Extract the CategoryName and Description
// from each result in the response.
// Build the output as a list
output = "<UL>";
for (var i = 0; i < categories.d.results.length; i++) {
var categoryName;
var description;
categoryName = categories.d.results[i].CategoryName;
description = categories.d.results[i].Description;
output += "<LI>" + categoryName + ":&nbsp;" +
description + "</LI>";
output += "</UL>";
document.getElementById("categories").innerHTML = output;
else {
var errordesc;
errordesc = "<P>Status code: " +
data.d.Invoke.StatusCode + "<br/>";
errordesc += response.get_body();
document.getElementById("categories").innerHTML = errordesc;
// Event handler for the error event.
// Render the response body in the placeholder.
// The 2nd argument includes the error message.
function errorHandler() {
document.getElementById("categories").innerHTML =
arguments[2];
})();
</script>
在“解决方案资源管理器”中,打开“AppManifest.xml”文件的快捷菜单,然后选择“查看代码”。
复制以下 RemoteEndPoints 定义作为 App 节点的子级。
<RemoteEndpoints>
<RemoteEndpoint Url=" http://services.odata.org" />
</RemoteEndpoints>
RemoteEndpoint 元素用于指定远程域。 Web 代理将验证发往远程域的请求是否已在外接程序清单中声明。 您最多可在 RemoteEndpoints 元素中创建 20 个条目。 仅考虑授权部分: http://domain:port
和 http://domain:port/website
被视为同一终结点。 您可以向同一个域中的很多不同的终结点(只有一个 RemoteEndpoint 定义)发出调用。
生成并运行解决方案
按 F5 键。
按 F5 键时,Visual Studio 会生成解决方案并部署加载项,同时还会打开加载项的权限页面。
选择“信任它”按钮。
单击“网站内容”页上的加载项图标。
下图显示了 SharePoint 网页中的远程数据。
SharePoint 网页中的远程数据
解决方案疑难解答
发生未处理异常“SP 未定义”。
确保可在浏览器窗口中访问 SP.RequestExecutor.js 文件。 如果要将本地服务器用作开发环境,则必须禁用 IIS 环回检查。
从 Windows PowerShell 命令提示符运行以下命令:New-ItemProperty HKLM:\System\CurrentControlSet\Control\Lsa -Name "DisableLoopbackCheck" -value "1" -PropertyType dword
警告:不建议在生产环境中禁用 IIS 环回检查。
来自远程终结点的响应的大小超过配置的限制。
Web 代理请求的响应大小不得大于 200 KB。
不支持方案-端口组合。
调用方案-端口组合必须满足以下条件:
方案 - 端口
http - 80
https - 443
http 或 https - 7000-10000
重要说明:出站端口取决于主机防火墙的可用性。 具体而言,只有 http-80 和 https-443 在 SharePoint Online 上可用。
代码示例:使用 Web 代理从远程服务中获取数据
在 SharePoint 中处理外部数据