Cross-Origin and Same-Origin Strategies: JSONP, CORS, Proxy, Nginx, WebSocket, postMessage, and document.domain

This article explains the concepts of cross‑origin and same‑origin policies, and demonstrates multiple solutions—including JSONP, CORS headers, proxy servers, Nginx configuration, WebSocket communication, postMessage, and document.domain—providing both front‑end and back‑end code examples for each method.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Cross-Origin and Same-Origin Strategies: JSONP, CORS, Proxy, Nginx, WebSocket, postMessage, and document.domain

Introduction: Cross-Origin and Same-Origin Policy

Cross‑origin occurs when a web page requests resources from a different origin (different protocol, domain, or port). The same‑origin policy protects user data by restricting direct communication between origins, with a few exceptions such as img, link, and script tags.

JSONP Implementation

JSONP bypasses the same‑origin restriction by using a script tag whose src attribute is not subject to the policy. The client supplies a callback parameter, the server wraps the data in a call to that function, and the browser executes the global callback.

function jsonp(url, cb) {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script');
    // Register a global callback
    window[cb] = function(data) {
      resolve(data);
    };
    // Set the script src with the callback query
    script.src = `${url}?cb=${cb}`;
    // Append to trigger the request
    document.body.appendChild(script);
  });
}

// Use the jsonp function
jsonp('http://localhost:3000', 'callback').then(res => {
  console.log(res); // output result
});

Backend for JSONP

const http = require('http');
http.createServer(function(req, res) {
  const query = new URL(req.url, `http://${req.headers.host}`).searchParams;
  if (query.get('cb')) {
    const cb = query.get('cb'); // e.g., 'callback'
    const data = 'hello world';
    const result = `${cb}("${data}")`;
    res.end(result);
  }
}).listen(3000);

CORS Implementation

CORS allows the server to specify permitted origins via the Access-Control-Allow-Origin response header, enabling the browser to relax the same‑origin check for the request.

// Front‑end request using XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:3000');
xhr.send();
xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    console.log(xhr.responseText);
  }
};
// Backend that sets CORS header
const http = require('http');
http.createServer((req, res) => {
  res.writeHead(200, {
    'Access-Control-Allow-Origin': 'http://127.0.0.1:5500'
  });
  res.end('Hello World');
}).listen(3000);

Proxy Server

A proxy forwards the request from the front‑end to the target server, acting as an intermediate layer that can add the appropriate CORS headers or simply hide the cross‑origin request from the browser.

// Front‑end request to proxy server
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://192.168.1.63:3000');
xhr.send();
xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    console.log(xhr.responseText);
  }
};
// Backend proxy implementation (Node.js)
const http = require('http');
http.createServer(function(req, res) {
  // Allow any origin
  res.writeHead(200, { "access-control-allow-origin": "*" });
  // Forward request to target server
  const options = {
    host: '192.168.1.63',
    port: '3000',
    path: '/',
    method: 'GET',
    headers: {}
  };
  http.request(options, proxyRes => {
    proxyRes.on('data', data => {
      res.end(data.toString());
    });
  }).end();
}).listen(3000);

Nginx Proxy

Using Nginx as a reverse proxy provides the same effect as a Node proxy, forwarding requests and optionally setting CORS headers. (Diagram omitted for brevity.)

WebSocket Implementation

WebSocket connections are not subject to the same‑origin policy in the same way as HTTP; they can be used for cross‑origin communication after the initial handshake.

// Front‑end helper using WebSocket
function myWebSocket(url, params = {}) {
  return new Promise((resolve, reject) => {
    const socket = new WebSocket(url);
    socket.onopen = () => {
      socket.send(JSON.stringify(params));
    };
    socket.onmessage = e => {
      resolve(e.data);
    };
  });
}

myWebSocket('ws://localhost:3000', {age: 18}).then(res => {
  console.log(res);
});
// Backend WebSocket server (Node.js with ws library)
const WebSocket = require('ws');
const ws = new WebSocket.Server({ port: 3000 });
ws.on('connection', client => {
  client.on('message', data => {
    client.send('Welcome');
    setInterval(() => {
      client.send('Ping');
    }, 2000);
  });
});

postMessage Communication

The postMessage API enables safe cross‑origin messaging between windows, iframes, or workers by specifying the target origin.

<!-- index.html (parent page) -->
<body>
  <h2>Home</h2>
  <iframe id="frame" src="http://127.0.0.1:5500/postMessage/detail.html" width="800" height="500"></iframe>
  <script>
    const obj = {name: 'midsummer', age: 18};
    document.getElementById('frame').onload = function() {
      this.contentWindow.postMessage(obj, 'http://127.0.0.1:8080');
      window.onmessage = e => console.log(e.data);
    };
  </script>
</body>
<!-- detail.html (iframe) -->
<body>
  <h3>Detail – <span id="title"></span></h3>
  <script>
    const title = document.getElementById('title');
    window.onmessage = e => {
      const {data: {name, age}, origin} = e;
      title.innerText = `${name} ${age}`;
      e.source.postMessage(`midsummer now ${++age} years`, origin);
    };
  </script>
</body>

document.domain Technique

When two pages share the same top‑level domain, setting document.domain to that shared domain relaxes the same‑origin restriction, allowing direct access between the pages.

<!-- index.html -->
<body>
  <h2>Home</h2>
  <iframe id="frame" src="http://127.0.0.1:5500/postMessage/detail.html" width="800" height="500"></iframe>
  <script>
    document.domain = '127.0.0.1';
    document.getElementById('frame').onload = function() {
      console.log(this.contentWindow.data);
    };
  </script>
</body>
<!-- detail.html -->
<script>
  document.domain = '127.0.0.1';
  var data = 'domain';
</script>

By setting the same document.domain value on both pages, the same‑origin restriction is effectively lifted, enabling seamless communication.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ProxyWebSocketCORSCross-OriginJSONPpostMessagesame-origin
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.