拓展边界:前端世界的跨域挑战

这篇具有很好参考价值的文章主要介绍了拓展边界:前端世界的跨域挑战。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

什么是跨域

概念

同源策略及限制内容

常见跨域场景

如何解决跨域

CORS

Nginx代理跨域

Node中间件代理跨域

WebSocket

postMessage

JSONP

其他


什么是跨域

概念

在此之前,我们了解一下一个域名地址的组成:

拓展边界:前端世界的跨域挑战,前端汇总,JavaScript,前端,javascript,跨域,同源策略,CORS,Nginx代理,JSONP

跨域指的是在网络安全中,由于浏览器的同源策略(Same-Origin Policy)限制,当一个网页的协议、域名或端口与另一个网页的协议、域名或端口不同时,就存在跨域问题。如果缺少同源策略的限制,可能会导致安全隐患,如跨站脚本攻击(XSS)或跨站请求伪造(CSRF)等。

同源策略及限制内容

同源策略是浏览器的一项安全机制,它限制了来自不同源的脚本对当前文档的访问。同源策略要求资源必须来自同一个源(即协议、域名和端口相同),并限制了对以下内容的访问:

  1. Cookie、LocalStorage、IndexedDB 等存储性内容:不允许在不同源之间读取或写入这些数据。

  2. DOM 节点:不允许获取来自不同源的 DOM 元素。

  3. AJAX 请求发送后的响应数据:如果发起了跨域的 AJAX 请求,浏览器会阻止读取其响应内容。

但是有三个标签允许跨域加载资源,它们不受同源策略限制:

  • <img src=XXX>
  • <link href=XXX>
  • <script src=XXX>

常见跨域场景

跨域存在于协议、子域名、主域名、端口号中任何一个不相同时。即使两个不同的域名指向同一个 IP 地址,只要其中任何一部分不同,就被视为不同源。

两个重要点:

  1. 协议和端口造成的跨域问题需要后端处理,前端无法解决。
  2. 浏览器在判断跨域时主要依据 URL 的首部,即协议、域名和端口必须匹配。

跨域并不是指请求发不出去,而是浏览器限制了读取来自其他域名下内容的安全策略。例如,Ajax 请求会被浏览器拦截响应数据,但表单提交不会获取新内容,所以可以发起跨域请求。同样,跨域并不能完全阻止 CSRF,因为请求依然会发送出去,只是浏览器会拦截响应。

如何解决跨域

CORS

CORS 通信过程都是浏览器自动完成,需要浏览器(都支持)和服务器都支持,所以关键在只要服务器支持,就可以跨域通信,CORS请求分两类:简单请求和非简单请求。

CORS请求默认不包含Cookie以及HTTP认证信息,如果需要包含Cookie,涉及跨域请求携带 Cookie 信息时需要一些特殊设置,其中涉及到 CORS 的头部设置以及前端代码的配置。

假设有两个域名:https://example.com 和 https://api.example.com,前者是网页的域名,后者是提供 API 的域名。下面是一个示例,演示如何设置跨域请求以在包含 Cookie 的情况下进行:

后端设置 CORS 头部

在 API 的响应中设置 CORS 相关头部:

// Express 示例
const express = require('express');
const app = express();
 
// 设置允许跨域请求的域名和允许携带 Cookie
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://example.com');
  res.header('Access-Control-Allow-Credentials', 'true');
  next();
});
 
// 处理其他路由或请求
// ...
 
app.listen(3000);

前端发送带有 withCredentials 的请求

在前端,如果想要在跨域请求中携带 Cookie,需要在 XMLHttpRequest 或 Fetch 请求中设置 withCredentials 为 true

使用 XMLHttpRequest 的示例:

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.withCredentials = true; // 允许携带 Cookie
xhr.send();

或者使用 Fetch API:

fetch('https://api.example.com/data', {
  method: 'GET',
  credentials: 'include', // 允许携带 Cookie
});

上述代码中的关键点在于将 withCredentials 或 credentials: 'include' 设置为 true,这样浏览器就会在请求中包含当前页面的 Cookie 信息。但要确保后端 API 设置了正确的 Access-Control-Allow-Origin 和 Access-Control-Allow-Credentials 头部,并且不要使用 * 通配符,而是指定了明确的允许跨域的域名。

简单请求

简单请求指的是符合一定条件的跨域请求类型,在这种请求下,浏览器会自动在头部中添加 Origin 字段,表示请求的来源域,服务器根据这个来源决定是否允许请求。满足以下两个条件之一的请求被认为是简单请求:

1.请求方法是 HEAD、GET、POST 之一

2.请求头信息不超过一定限制。允许的请求头包括:

  • Accept

  • Accept-Language

  • Content-Language

  • Last-Event-Id

  • Content-Type:允许的值为 application/x-www/form/urlencoded、multipart/form-data、text/plain 之一。

这些条件主要为了兼容早期的表单提交方式,因为历史上表单提交一直可以跨域。

在这样的简单跨域请求中,服务器至少需要设置 Access-Control-Allow-Origin 头部来允许特定来源的请求。如果服务器认可请求,会在响应中返回以下必要的 CORS 头部:

Access-Control-Allow-Origin 这个字段是必须的,它指定了允许访问的来源域,一般是请求中 Origin 字段的值,但也可以是通配符 *,表示允许任意来源。
Access-Control-Allow-Credentials 这个字段是可选的,表示是否允许发送 Cookie。如果需要跨域请求携带身份凭证(比如 Cookie 或 HTTP 认证信息),服务器需要设置这个字段为 true。
Access-Control-Expose-Headers 这个字段是可选的,它指定了响应中可以被前端访问的其他头部信息。
Content-Type 表示响应的文档类型和字符编码。

简单请求的处理相对较为简单,但需要服务器允许特定的跨域访问并设置相应的 CORS 头部来确保安全。

非简单请求

非简单 CORS 请求指的是不符合简单请求条件的跨域请求,如使用了 PUT 或 DELETE 方法,或者请求的 Content-Type 是 application/json 等。对于这样的请求,浏览器会在正式发起请求之前先发送一个 OPTIONS 类型的预检请求。

预检请求的目的是向服务器查询是否允许来自网页所在域名的请求,并了解可以使用哪些额外的头信息字段。这个预检请求(OPTIONS 请求)的头部信息包括:

  • Origin: 标识请求来自哪个域,是必须的字段。
  • Access-Control-Request-Method: 列出 CORS 请求会用到的 HTTP 方法,也是必须的字段。
  • Access-Control-Request-Headers: 指定 CORS 请求会额外发送的头信息字段,用逗号隔开。

服务器收到这个预检请求后,根据收到的信息判断是否允许这个请求,如果允许,则返回相应的 CORS 头部信息。除了允许特定的跨域请求,服务器还可以在响应头部中添加 Access-Control-Max-Age 字段来缓存预检请求的结果,减少后续请求的预检次数。这个缓存只对完全一样的 URL 生效,超出缓存时间后,再次发起相同的跨域请求仍会触发预检请求。

Nginx代理跨域

Nginx可以用作反向代理服务器,来解决跨域问题。它可以代理客户端的请求,并将请求发送到目标服务器,再将目标服务器的响应返回给客户端。这种方法类似于 CORS 跨域原理,但是它是通过服务器端进行设置,而不是在浏览器端进行设置。

以下是一个简单的 Nginx 配置示例,用于处理跨域请求:

server {
    listen 81;
    server_name www.domain1.com;
 
    location / {
        # 设置反向代理
        proxy_pass http://xxxx1:8080;
 
        # 修改 Cookie 中的域名
        proxy_cookie_domain www.xxxx1.com www.xxxx2.com;
 
        # 添加头部信息以处理跨域请求
        add_header Access-Control-Allow-Origin http://www.xxxx2.com; # 当前端只跨域不带 Cookie 时,可以使用 * 
        add_header Access-Control-Allow-Credentials true;
    }
}

这段配置的作用如下:

proxy_pass 指令用于指定反向代理的目标服务器地址。proxy_cookie_domain 用于修改代理服务器返回的响应中的 Cookie 中的域名,将它从源域名修改为目标域名,确保 Cookie 在跨域时仍然有效。add_header 指令用于添加响应头部信息,其中 Access-Control-Allow-Origin 允许特定来源的跨域请求,Access-Control-Allow-Credentials 表示是否允许请求携带身份凭证(例如 Cookie)。

这种方法通过 Nginx 作为代理服务器,处理了跨域请求的响应头部,允许指定的域名进行跨域请求。这样就可以在不修改前端代码的情况下,实现跨域请求的需求。

Node中间件代理跨域

在 vue.config.js 文件中,可以通过配置 devServer 的 proxy 选项实现代理转发:

module.exports = {
    // 其他配置...
    devServer: {
        proxy: {
            [process.env.VUE_APP_BASE_API]: {
                target: 'http://xxxx', // 代理跨域目标接口
                ws: true,
                changeOrigin: true,
                pathRewrite: {
                    ['^' + process.env.VUE_APP_BASE_API]: ''
                }
            }
        }
    }
}
  • proxy 字段用于配置代理。process.env.VUE_APP_BASE_API 是 Vue 项目中定义的环境变量,表示需要被代理的请求路径前缀。

  • target 指定了代理的目标地址,即请求将会被代理到这个地址下。

  • ws 表示是否代理 WebSocket。

  • changeOrigin 设置为 true 后,可以突破浏览器的同源策略,允许跨域。

  • pathRewrite 允许对请求路径进行重写,将匹配到的路径前缀去掉。比如,如果请求路径是 /api/user,经过 pathRewrite 后就会变成 /user,将前缀 /api 去掉了。

当使用 Node 中间件进行代理跨域时,你可以使用 http-proxy-middleware 包来创建一个代理服务器,让后端服务(如 Express)处理跨域请求。这个中间件可以在 Express 应用程序中使用,允许你在服务器端修改请求和响应,以便处理跨域问题。

下面是一个在 Express 中使用 http-proxy-middleware 中间件的简单示例:

const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
 
const app = express();
 
app.use('/', createProxyMiddleware({ 
    // 代理跨域目标接口 
    target: 'http://xxxx:8080', 
    changeOrigin: true, 
    // 修改响应头信息,实现跨域并允许带cookie 
    onProxyRes: function(proxyRes, req, res) { 
        res.header('Access-Control-Allow-Origin', 'http://xxxx');
        res.header('Access-Control-Allow-Credentials', 'true');
    }, 
    // 修改响应信息中的 cookie 域名 
    cookieDomainRewrite: 'www.domain1.com' // 可以为 false,表示不修改
})); 
 
app.listen(3000);

这段代码做了以下事情:

  • 引入了 Express 框架和 http-proxy-middleware。

  • 创建了一个 Express 应用。

  • 使用 app.use 将 createProxyMiddleware 中间件应用到根路径 /。

  • 配置了 createProxyMiddleware,指定了目标服务器的地址 target,开启了 changeOrigin 选项以确保源头地址被更改为目标地址。

  • 在 onProxyRes 中修改了响应头部信息,允许跨域并设置了允许携带凭证(如 Cookie)。

  • cookieDomainRewrite 可以用于修改响应信息中的 Cookie 域名,使其在传输中适应跨域情况。

这种方式可以在后端服务器层面对跨域进行处理,允许前端应用向不同域名的后端服务发出请求。

WebSocket

WebSocket是一种在单个 TCP 连接上进行全双工通信的协议,它允许客户端和服务器之间进行实时数据交换。与传统的 HTTP 请求不同,WebSocket 的连接是持久性的,双方可以随时发送数据而不需要等待请求。

在跨域方面,WebSocket协议与传统的 HTTP 请求不同,它不受同源策略的限制。可以使用 ws://(非加密)和 wss://(加密)作为协议前缀,不受同源策略的约束,只要服务器支持 WebSocket,即可与客户端进行通信。

WebSocket请求头中包含 Origin 字段,用于指示请求的来源域。服务器可以检查这个字段来判断是否允许与特定域的客户端建立 WebSocket 连接。如果客户端的来源域在服务器的白名单内,服务器将允许该连接的建立,否则可能会拒绝连接或执行其他安全措施。

通过 WebSocket,服务器和客户端之间可以进行持久的双向通信,这种通信方式适用于实时性要求较高的场景,如在线聊天、实时数据传输等。由于不受同源策略的限制,WebSocket提供了一种跨域通信的可选方案。

下面是一个简单的例子,展示了如何使用 WebSocket 进行跨域通信。

首先,假设有两个域名分别是 domain1.com 和 domain2.com,我们将在 domain1.com 的页面上创建 WebSocket 连接到 domain2.com 的服务器:

在 domain2.com 的服务器端,你需要有一个 WebSocket 服务器,例如基于 Node.js 的 ws 模块,用于监听 WebSocket 连接:

const WebSocket = require('ws');
 
const wss = new WebSocket.Server({ port: 8080 });
 
wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    console.log('Received: %s', message);
    // 可以回复客户端消息
    ws.send('Hello, client!');
  });
});

在 domain1.com 的页面上,你可以使用 JavaScript 来创建 WebSocket 连接到 domain2.com 的服务器:

const socket = new WebSocket('ws://domain2.com:8080'); // WebSocket服务器的地址
 
socket.onopen = function(event) {
    console.log('WebSocket连接已打开');
    socket.send('Hello, server!');
};
 
socket.onmessage = function(event) {
    console.log('收到服务器消息:', event.data);
};
 
socket.onclose = function(event) {
    if (event.wasClean) {
        console.log('连接已关闭');
    } else {
        console.log('连接断开');
    }
};
 
socket.onerror = function(error) {
    console.error('WebSocket连接错误:', error);
};

在这个例子中,domain1.com 的页面通过 WebSocket 连接到了 domain2.com 的服务器,并向其发送了消息。服务器收到消息后可以进行处理,并且也可以通过 WebSocket 向客户端发送消息。

需要注意的是,WebSocket 协议在设计上允许跨域通信,因此不会受到浏览器同源策略的限制。但是,服务器端仍然可以根据自己的逻辑来判断是否接受来自特定来源的连接。

postMessage

postMessage 是 HTML5 中的一项 API,它允许在不同窗口(包括 iframe)或不同来源的文档间进行安全地消息传递。这种通信机制可以用于多种场景:

1️⃣ 页面和新打开的窗口之间的数据传递

2️⃣ 不同窗口(包括不同域的窗口)之间的通信

3️⃣ 页面与嵌套的 iframe 之间的数据传递

4️⃣ 不同源的跨域传递数据

postMessage 接受两个参数:

第一个参数是要发送的数据,可以是字符串、对象等。

第二个参数是指定消息发送的目标窗口的来源。这个参数通常是一个目标窗口的 origin(协议 + 域名 + 端口),也可以是通配符 *(表示任意窗口),或者 /(表示与当前窗口同源的窗口)。

例如,在一个页面中,可以使用以下方式向另一个窗口发送消息:

// 获取目标窗口对象
const targetWindow = window.open('https://example.com', '_blank');
 
// 向目标窗口发送消息
targetWindow.postMessage({ message: 'Hello, window!', value: 42 }, 'https://example.com');

在目标窗口中,可以监听 message 事件来接收来自其他窗口的消息:

// 监听 message 事件
window.addEventListener('message', function(event) {
    // 判断消息来源是否符合预期
    if (event.origin === 'https://sending-origin.com') {
        // 处理接收到的消息
        console.log('Received message:', event.data);
    }
});

JSONP

JSONP(JSON with Padding)是一种利用 <script> 标签实现的跨域数据请求方法。其原理是通过动态创建 <script> 标签,向服务器请求数据,并在请求的 URL 中包含一个回调函数名。服务器收到请求后,将数据包裹在回调函数中返回给客户端,从而绕过浏览器的同源策略限制。

JSONP 主要用于 GET 请求,并不适用于其他 HTTP 方法,且存在安全隐患,容易受到 XSS(跨站脚本攻击)的影响。但它有一些优点,比如可以向不支持 CORS 的旧浏览器或不支持跨域请求的网站请求数据。

使用 JSONP 的示例代码如下:

// 创建一个包含回调函数的 URL
const url = 'http://juejin.com/xxx?callback=handleCallback';
 
// 创建一个 script 标签
const script = document.createElement('script');
 
// 设置 script 的 URL
script.src = url;
 
// 将 script 添加到页面中
document.body.appendChild(script);
 
// 定义回调函数,处理从服务器返回的数据
function handleCallback(res) {
    console.log(res);
}

服务器接收到这个请求后,会将数据放在 handleCallback 函数中返回,例如:

handleCallback({ code: 200, msg: 'success', data: [] });

在客户端,这个函数 handleCallback 将立即执行,从而完成数据的处理和操作。

虽然 JSONP 具有一定的局限性和安全风险,但在某些场景下仍然是一种有效的跨域数据获取方式。

其他

除了以上提到的一些常见的解决跨域的方法以外,还有其他的方式可以来解决这个问题。

1. document.domain + iframe:适用于主域名相同但子域名不同的跨域场景。当两个页面的 document.domain 设置为同一个值(主域名),它们就可以相互通信。但这种方法仅适用于主域名相同的情况。

2. window.name + iframe:利用 iframe 的 window.name 属性,这个属性在不同页面或者不同域名加载后依然保持不变。通过在不同页面的 iframe 中设置和读取 window.name,可以实现跨域通信。window.name 具有持久性,且可以存储较大量的数据。

3. location.hash + iframe:适用于页面间利用 URL 的 hash 部分来传递信息,特别是在 C 页面帮助 A 页面和 B 页面进行通信。通过改变 URL 的 hash 部分来传递信息,在不同页面之间进行简单的数据交换。

这些方法虽然可以解决一些特定的跨域通信问题,但由于它们的特性和限制,通常只适用于特定场景,并且可能存在一些安全性或者容量方面的限制。因此,在使用这些方法时,需要仔细考虑其适用范围和可能带来的安全隐患。

好啦,本文就到这里结束了,感谢阅读~~文章来源地址https://www.toymoban.com/news/detail-810805.html

到了这里,关于拓展边界:前端世界的跨域挑战的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 常见的跨域解决方案

    常见的跨域解决方案: 跨域问题可以分为两种情况: 前端跨域和后端跨域 。以下是针对这两种情况的跨域解决方案: 前端跨域解决方案: JSONP: 适用于前端向不同域名下的服务器请求数据,通过添加回调函数名称来实现跨域数据获取。 CORS: 当前端向服务器请求数据时,

    2024年02月12日
    浏览(47)
  • 跨域介绍及Java中常见的跨域解决方案

    跨域(Cross-Origin)指的是在浏览器中,由于安全策略的限制,当前网页的 JavaScript 代码无法直接访问不同源(协议、域名、端口)的资源。这意味着如果网页尝试通过 AJAX、Fetch 或 WebSocket 等方式向不同源的服务器发送请求,浏览器会阻止这些请求,从而避免潜在的安全风险。

    2024年02月07日
    浏览(37)
  • Chrome浏览器的跨域设置

    做前后端分离的开发的时候,出于一些原因往往需要将浏览器设置成支持跨域的模式,而且chrome浏览器支持可跨域的设置,但是新版本的chrome浏览器提高了跨域设置的门槛,原来的方法不再适用了。其实网上也有很多大神总结的chrome跨域设置教程,都是差不多。 下载好谷歌浏

    2024年02月02日
    浏览(83)
  • ICML 2023 | 拓展机器学习的边界

    编者按:如今,机器学习已成为人类未来发展的焦点领域,如何进一步拓展机器学习技术和理论的边界,是一个极富挑战性的重要话题。7月23日至29日,第四十届国际机器学习大会 ICML 2023 在美国夏威夷举行。该大会是由国际机器学习学会(IMLS)主办的年度机器学习国际顶级

    2024年02月15日
    浏览(42)
  • chrome浏览器跨域设置(版本号108之后的跨域设置)

    1、首先在chrome浏览器安装目录下复制chrome.exe,生成一个新的命名为chrome-cross.exe 注意:为什么要在目录下复制一个新的?是因为如果名字相同,可能会导致设置好的跨域浏览器打开后跟原来的chrome.exe是同一个浏览器,设置的跨域浏览器就不是生效了。 2、点击 chrome-cross.exe

    2024年02月15日
    浏览(54)
  • 漏了一个“/”导致的跨域错误(CORS)

    在成功搭建好DRF(Django rest framework)的Blog的backend后,昨天开始搭建Vue3+axios+pinia+element_plus的前台服务. 开始一切顺利,到第一个axios的get处理的时候,出现了错误. axios相关的代码如下:   在Pinia的Store中调用axios.get方法取得Backend端的Tag数据 目前的代码不严谨,没有进行错误处理. 在Ch

    2023年04月21日
    浏览(43)
  • 解决系统开发中的跨域问题:CORS、JSONP、Nginx

    本博客配套的源码在这里 最近我在做一个系统的全栈开发,遇到了这样一个问题。 首先,我的前端是一个来自百度的开源框架——Amis,它封装自React.js,基于JSON配置。我下载了Amis提供的SDK文件夹,并进行了代码开发。但是我在部署整个系统的时候遇到了跨域问题。原因是,

    2024年01月20日
    浏览(56)
  • pdf格式文件下载不预览,云存储的跨域解决

    后端接口中返回的是pdf文件路径比如: pdf文件路径 (https://wangzhendongsky.oss-cn-beijing.aliyuncs.com/wzd-test.pdf) 前端适配是这样的 点击后预览 但是客户方要求不预览点击后直接下载 示例演示  (pdf下载 - 码上掘金) 有pdf链接的可以跨过该阶段 登陆阿里云平台 1. 点击又上角的控

    2024年02月11日
    浏览(37)
  • 解决Spring Boot前后端分离开发模式中的跨域问题

    在实际开发中,经常会遇到前端Vue应用与后端Spring Boot API接口存在跨域访问的问题。本篇博客将分享解决Spring Boot前端Vue跨域问题的实战经验,帮助开发者快速解决该问题。 跨域问题是由于浏览器的同源策略引起的。同源策略限制了从一个源加载的文档或脚本如何与来自另一

    2024年02月10日
    浏览(91)
  • node+vue开发环境下接口数据传递中的跨域问题

    大部分浏览器自带的保护措施,限制用户在一个域名下请求另一个域名的数据 跨域对于前后端开发者来说,就像一块狗皮膏药,无论是面试还是开发中,都会经常遇到。 之所以出现跨域问题,是因为浏览器的同源策略,为了隔离潜在的恶意文件,为了防御来自歪门邪道的攻

    2024年01月24日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包