WebPivotTable is a client-side web component. When it needs to fetch a data file or connect to an OLAP server hosted on a different domain, the browser's Same-Origin Policy will block the request. This page explains the problem and the proxy solution built into WPT.
Same-Origin Policy
The Same-Origin Policy is a browser security model that restricts scripts on one origin from reading data on another origin. Two URLs share the same origin only when their protocol, host, and port all match.
For example, comparing against http://www.example.com/dir/page.html:
| Compared URL | Outcome | Reason |
|---|---|---|
http://www.example.com/dir/page2.html |
Same origin | Same protocol, host, port |
http://www.example.com:81/dir/other.html |
Blocked | Different port |
https://www.example.com/dir/other.html |
Blocked | Different protocol |
http://en.example.com/dir/other.html |
Blocked | Different host |
When WebPivotTable tries to load a CSV or Excel file from another domain, or connect to an OLAP server on a different host/port, the browser blocks the request.
CORS
Cross-Origin Resource Sharing (CORS) lets a server opt-in to cross-origin requests by returning specific HTTP headers. However, you must control the remote server to enable CORS -- which is often not possible with third-party data sources or OLAP servers.
Proxy Solution
The Same-Origin Policy only applies to browsers. A server can fetch any URL without restriction. A proxy accepts requests from the browser, forwards them to the remote server, and returns the response -- bypassing the Same-Origin restriction entirely.
Browser --> Proxy (same origin) --> Remote Server (different origin)
<-- <--
WebPivotTable includes two proxy endpoints to handle the two common cross-origin scenarios:
| Proxy | Endpoint | Purpose |
|---|---|---|
| File Proxy | POST /api/wpt/file-proxy |
Fetch remote CSV, Excel, WPT, or web-service data files |
| XMLA Proxy | POST /api/wpt/xmla-proxy |
Forward SOAP/XML requests to a remote OLAP server |
File Proxy (/api/wpt/file-proxy)
Fetches a remote file on behalf of the WPT component.
Request:
POST /api/wpt/file-proxy
X-File-Url: https://example.com/data/sales.csv
The target URL is passed in the X-File-Url header. The proxy fetches that
URL server-side and streams the response back with the original Content-Type.
Used by: setWptFromCsvUrl, setWptFromExcelUrl, setWptFromWebService,
setWptFromWptUrl, and related APIs when the data file is on a different origin.
XMLA Proxy (/api/wpt/xmla-proxy)
Forwards XMLA (XML for Analysis) SOAP requests to a remote OLAP server.
Request:
POST /api/wpt/xmla-proxy
X-Xmla-Url: https://olap-server.example.com/xmla
Content-Type: text/xml; charset=utf-8
The target XMLA endpoint is passed in the X-Xmla-Url header. The SOAP body
is forwarded as-is. The SOAPAction header is also forwarded when present.
Used by: setWptFromOlapCube and OLAP-related operations.
Security
Both proxies include the following safeguards:
- URL validation -- only
http://andhttps://URLs are accepted - Rate limiting -- excessive requests from a single client are rejected
- CORS headers -- responses include
Access-Control-Allow-Origin: *so any page embedding WPT can call them
Default Proxy Server
By default, WebPivotTable points to the public proxy hosted at
https://new.webpivottable.com:
// Default server options (built into WPT)
{
server: {
fileProxyEnabled: 1,
fileProxy: 'https://new.webpivottable.com/api/wpt/file-proxy',
xmlaProxyEnabled: 1,
xmlaProxy: 'https://new.webpivottable.com/api/wpt/xmla-proxy'
}
}
This means cross-domain loading works out of the box -- no server setup required.
Using Your Own Proxy
If you prefer to route proxy traffic through your own server, you can set up a simple Express server. Here is a complete, ready-to-use example:
1. Install dependencies
npm install express cors request body-parser morgan method-override
2. Create the proxy services (services.js)
"use strict";
var request = require("request");
// Forward XMLA SOAP requests to a remote OLAP server
exports.xmlaProxy = function(req, res) {
req
.pipe(
request(req.headers["x-xmla-url"]).on("error", function(err) {
res.send(400, err);
})
)
.pipe(res);
};
// Fetch a remote file (CSV, Excel, WPT, etc.) on behalf of the browser
exports.fileProxy = function(req, res) {
try {
request
.get(req.headers["x-file-url"])
.on("error", function(err) {
res.send(400, err);
})
.pipe(res);
} catch (error) {
res.send(500, req.headers["x-file-url"] + " is not available!");
}
};
3. Create the server (server.js)
var express = require("express"),
bodyParser = require("body-parser"),
cors = require("cors"),
services = require("./services.js"),
app = express();
app.use(cors());
app.use(bodyParser.json({ limit: "100mb" }));
app.use(bodyParser.urlencoded({ limit: "100mb", extended: true }));
app.post("/wpt/fileProxy", services.fileProxy);
app.post("/wpt/xmlaProxy", services.xmlaProxy);
app.listen(process.env.PORT || 8003);
console.log("Proxy server listening on port " + (process.env.PORT || 8003));
4. Start the server
node server.js
5. Point WPT to your proxy
const wpt = document.getElementById('wpt');
wpt.setOptions({
server: {
fileProxy: 'https://your-server.com/wpt/fileProxy',
xmlaProxy: 'https://your-server.com/wpt/xmlaProxy'
}
});
You can also disable the proxy entirely if all your data sources are same-origin or CORS-enabled:
wpt.setOptions({
server: {
fileProxyEnabled: 0,
xmlaProxyEnabled: 0
}
});
See Options for the full list of server-related settings.