网站改版好吗,天心区网站建设公司,网站建设 维护,手机网站建设方法这篇文章主要介绍了跨域问题#xff0c;包括其定义、产生原因及各种解决方法。原因是浏览器安全策略限制#xff0c;方法有 JSONP、CORS、Domain、 postMessage、Nginx配置、.NetCore配置。 前言 什么是跨域问题? 在Web应用中#xff0c;当一个网页的脚本试图去请求另一个域… 这篇文章主要介绍了跨域问题包括其定义、产生原因及各种解决方法。原因是浏览器安全策略限制方法有 JSONP、CORS、Domain、 postMessage、Nginx配置、.NetCore配置。 前言 什么是跨域问题? 在Web应用中当一个网页的脚本试图去请求另一个域名下的资源时就会遇到跨域问题。跨域问题是由浏览器的同源策略所引起的。换句话说后端返回给浏览器的数据会被浏览器的同源策略给拦截下来。
同源策略要求资源的协议、域名和端口号都必须相同才能确保数据的安全性。如果不满足这个条件请求将被浏览器拒绝从而导致跨域问题的出现。
同源策略 协议号-域名-端口号 都相同的地址浏览器才认为是同源
协议号域名端口号 / 路径https://192.168.31.45:8080/userhttps://192.168.31.45:8080/list
上面这个例子虽然它们的路径不一样但是协议号、域名、端口号都相同所以它们就是同源的 跨域问题的原因?
跨域问题主要是由于浏览器的安全策略限制引起的。同源策略的目的是保护用户的隐私和数据安全防止恶意网站获取用户的敏感信息或进行未授权的操作。 通过限制跨域请求浏览器有效地减少了许多网络攻击的风险例如跨站脚本攻击XSS和跨站请求伪造CSRF。 JSONP
JSONPJSON with Padding是一种用于解决跨域请求的技术它利用了 script 标签可以跨域加载资源的特性。
下面是 JSONP 解决跨域请求的基本原理 前端发起 JSONP 请求 前端页面通过动态创建 script 标签设置其 src 属性为包含回调函数的 URL。通常这个 URL 是指向另一个域名下的服务器接口。 服务端返回数据 服务端接收到 JSONP 请求后会将数据包装在回调函数中返回给前端。这样前端页面就可以获得跨域请求返回的数据。 前端处理数据 前端页面定义好与回调函数同名的 JavaScript 函数当服务端返回数据时会执行这个函数并传入返回的数据作为参数从而实现跨域数据的获取和处理。 前端代码
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
bodybutton idbtn获取数据/buttonscript// 定义一个函数 jsonp用于发送 JSONP 请求function jsonp(url, cb) {return new Promise((resolve, reject) {// 创建一个 script 标签const script document.createElement(script);// 设置 script 的 src 属性包含了请求的 URL 和回调函数名称script.src ${url}?cb${cb}; // http://localhost:3000?cbcallback// 将 script 添加到文档中document.body.appendChild(script); // 浏览器自动请求 src 中的内容// 定义一个全局函数用于处理返回的数据window[cb] (data) {resolve(data)}})}// 获取按钮元素let btn document.getElementById(btn);// 绑定点击事件btn.addEventListener(click, () {// 发送 JSONP 请求jsonp(http://localhost:3000, callback).then(res {console.log(后端的返回结果 res);})})/script
/body
/html后端代码
const Koa require(koa);
const app new Koa();// 定义中间件函数 main处理请求并返回数据
const main (ctx, next) {console.log(ctx.query); // 输出请求参数对象 { cb: callback }// 从请求参数中获取回调函数名称const cb ctx.query.cb;// 准备要返回给前端的数据const data 给前端的数据;// 构造带有回调函数名称的字符串格式为 callback(给前端的数据)const str ${cb}(${data});// 将构造好的字符串作为响应体返回给前端ctx.body str;
}// 将 main 中间件注册到 Koa 应用中
app.use(main);// 监听 3000 端口启动服务器
app.listen(3000, () {console.log(listening on port 3000);
})优点
简单易用 JSONP 实现简单只需在前端添加一个 script 标签即可完成跨域请求无需复杂的配置。兼容性好 JSONP 能够兼容各种浏览器包括早期版本的浏览器因为它是通过动态创建 script 标签实现的。支持跨域请求 JSONP 可以在不同域之间进行数据通信解决了传统 AJAX 请求受同源策略限制的问题。
缺点
安全性问题 JSONP 存在安全风险因为它是通过在前端动态加载脚本来获取数据可能会被用于注入恶意脚本导致安全漏洞。只支持 GET 请求 JSONP 只能发起 GET 请求无法支持其他类型的 HTTP 请求如 POST、PUT 等。依赖服务端支持 JSONP 需要服务端返回数据时将其包裹在一个回调函数中因此需要服务端提供支持如果服务端不支持 JSONP 格式返回数据则无法使用该方法。 CORS跨域资源共享
CORS是一种机制允许服务器在响应中携带一个特殊的标头以告知浏览器该服务器允许哪些源的网页访问其资源。 可以总结为一句话后端通过设置响应头来告诉浏览器不要拒绝接受后端的响应。
前端代码在用户点击按钮时通过发送跨域请求获取服务器返回的数据并将数据打印到浏览器的控制台
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
bodybutton idbtn获取数据/buttonscriptlet btn document.getElementById(btn);btn.addEventListener(click, () {fetch(http://localhost:3000) // 发送跨域请求到服务器.then(res res.json()).then((res) {console.log(res); // 打印返回的数据到控制台})})/script
/body
/html代码实现了以下功能
在 HTML 中定义了一个按钮元素id 为 btn用于触发发送数据请求。在 JavaScript 部分使用 fetch 函数发送 GET 请求到指定的服务器地址 http://localhost:3000。在成功接收到服务器响应后使用 .then 方法将响应解析为 JSON 格式。在第二个 .then 方法中处理解析后的数据并将其输出到浏览器的控制台。 后端代码 Node.js 服务器代码创建了一个 HTTP 服务器监听在端口 3000。当接收到请求时返回一个包含 hello cors 消息的 JSON 数据。
const http require(http);const server http.createServer((req, res) {res.writeHead(200, {// cros实现原理Access-Control-Allow-Origin: http://127.0.0.1:5500 // 允许来自指定地址的跨域请求})let data {msg: hello cors}res.end(JSON.stringify(data)) // 返回数据给前端页面
})server.listen(3000, () {console.log(listening on port 3000);
})后端代码第6行在服务端设置响应头来控制跨域访问。
常见的响应头包括 Access-Control-Allow-Origin指定允许访问的域名。 例如Access-Control-Allow-Origin: *表示允许所有域名访问 而Access-Control-Allow-Origin:http://127.0.0.1:5500表示只允许特定域名访问。 Access-Control-Allow-Methods指定允许的HTTP方法。 Access-Control-Allow-Headers指定允许的自定义请求头。
CORS支持各种类型的HTTP请求包括GET、POST等。 Domain
我们还可以使用 Domain 方法来解决一些特定情况下的跨域访问问题。 在跨域通信时还需要注意以下几点 页面的域名必须满足 Domain 方法的限制即二级域名相同如 example.com。 父级页面需要在设置 document.domain 之前定义需要共享的变量或对象。 子级页面可以通过 window.parent 来访问父级页面的属性或变量但需要确保父级页面已经加载完成并且两者的域名设置已生效。
下面举一个简单的例子来说明 Domain 方法的用法
假设有两个页面分别位于不同子域名下一个是 parent.example.com另一个是 child.example.com。我们希望这两个页面能够进行跨域通信。
在父级页面 parent.example.com/index.html 中的代码如下
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleParent Page/title
/head
bodyh1Parent Page/h1iframe srchttp://child.example.com/child.html/iframescriptdocument.domain example.com;var messageFromParent Hello from parent page!;/script
/body
/html在子级页面 child.example.com/child.html 中的代码如下
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleChild Page/title
/head
bodyh1Child Page/h1scriptdocument.domain example.com;var messageFromChild Hello from child page!;// 访问父级页面定义的变量var message window.parent.messageFromParent;console.log(Message from parent: message);/script
/body
/html在这个例子中父级页面和子级页面分别设置了相同的 document.domain 为 example.com以实现二级域名相同。
父级页面定义了一个名为 messageFromParent 的变量子级页面在加载后通过 window.parent 来访问父级页面定义的变量并打印出父级页面的消息。
通过设置相同的 document.domain父子页面之间就可以进行跨域通信实现数据共享和交互。 postMessage
使用 postMessage() 方法结合 iframe 元素可以实现跨域通信这是一种常见的技术。通过在父窗口和嵌套的 iframe 之间使用 postMessage() 方法可以安全地在不同源之间进行通信。
iframe 可以用于解决跨域通信的问题其原理是利用浏览器中同源策略的限制将不同域的内容加载到独立的 iframe 中通过 postMessage 方法进行跨文档通信。
在 a.html 文件中
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
bodyh2a.html/h2!-- 创建一个 iframe 元素来加载 b.html --iframe srchttp://127.0.0.1:5500/postMessage/b.html frameborder0 idiframe/iframescript// 向 b.html 发送数据let iframe document.getElementById(iframe);iframe.onload function() {// 准备要发送的数据let data {name: Tom};// 通过 postMessage 方法向 iframe 发送数据iframe.contentWindow.postMessage(JSON.stringify(data), http://127.0.0.1:5500);}// 监听来自 b.html 的消息window.addEventListener(message, function(e) {console.log(e.data);});/script
/body
/html在 b.html 文件中
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
bodyh4b.html/h4script// 监听来自父页面的消息window.addEventListener(message, function(e) {console.log(JSON.parse(e.data));if (e.data) {// 收到消息后延迟 2 秒发送回应给父页面setTimeout(function() {window.parent.postMessage(我接受到, http://127.0.0.1:5500);}, 2000);}});/script
/body
/html优点
安全性 使用 iframe 结合 postMessage 进行跨域通信是一种相对安全的方法能够避免常见的跨站脚本攻击XSS。灵活性 可以在不同域之间传递数据实现更丰富的交互体验如单点登录、共享数据等。适用性广泛 跨域通信是 Web 开发中常见需求而 iframe 结合 postMessage 是一种通用且有效的解决方案。
缺点
复杂性 跨域通信涉及到多个文档之间的交互需要额外的处理和编码增加了开发的复杂度。性能开销 使用 iframe 进行跨域通信可能会引入额外的网络请求和资源加载对页面加载性能有一定影响。兼容性 旧版本的浏览器可能对 postMessage 支持不完整需要做兼容性处理。 Nginx
nginx反向代理 配置
这个配置允许任何域通过GET、POST和OPTIONS方法访问资源并且允许一些常见的头信息字段。Access-Control-Max-Age 指令用于指定预检请求的结果能被缓存多久。
确保在实际部署时根据安全和需求情况将Access-Control-Allow-Origin设置为特定域而不是*表示允许所有域以减少跨站脚本攻击XSS的风险。
server {listen 80;server_name example.com;location / {# 设置允许跨域的域* 表示允许任何域也可以设置特定的域add_header Access-Control-Allow-Origin *;# 允许的方法add_header Access-Control-Allow-Methods GET, POST, OPTIONS;# 允许的头信息字段add_header Access-Control-Allow-Headers User-Agent,Keep-Alive,Content-Type;# 缓存时间add_header Access-Control-Max-Age 1728000;# 其他配置...}# 其他 server 配置...
} .NetCore
在.NET Core中配置跨域非常简单。你可以在Startup.cs文件中的ConfigureServices方法添加跨域服务并在Configure方法中配置跨域。
public class Startup
{// ...// 在ConfigureServices方法中添加跨域服务public void ConfigureServices(IServiceCollection services){// ...services.AddCors(options {options.AddPolicy(CorsPolicy,builder builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());});}// 在Configure方法中配置跨域public void Configure(IApplicationBuilder app, IWebHostEnvironment env){// ...// 使用跨域策略app.UseCors(CorsPolicy);// ...}
}