当前位置:首页 > 技术文章 > 正文内容

深入理解跨域及跨域请求数据方式

arlanguage4个月前 (12-26)技术文章35

#网络安全##http##跨域#

一、跨域概念解析

跨域是一个在前端开发中经常遇到的问题。它指的是浏览器不能执行其他网站的脚本,这是由于浏览器的同源策略造成的。所谓同源,即协议、域名、端口都要相同。只要这三个要素中有任何一个不同,都被当作是不同的域,就会产生跨域问题。

同源策略是浏览器最核心也最基本的安全功能。如果缺少了同源策略,浏览器很容易受到 XSS、CSFR 等攻击。同源策略具体限制内容包括:

  • Cookie、LocalStorage 和 IndexDB 无法读取:不同源的文档之间不能读取对方的存储内容。
  • DOM 无法获得:不能获取非同源网页的 DOM。
  • AJAX 请求不能发送:不能向非同源之地发送 ajax 请求。

例如,假设有两个网站,A 网站部署在 http://localhost:81,B 网站部署在 http://localhost:82。当 A 网站的页面想去访问 B 网站的信息时,就会出现跨域问题。因为它们的端口不同,不满足同源策略的要求。

总之,同源策略的存在是为了保护用户的安全和隐私,但在某些情况下,也给开发带来了一些挑战。开发人员需要了解跨域问题的本质,并掌握一些解决跨域问题的方法,以确保应用程序的正常运行。

二、跨域请求方式大揭秘

(一)JSONP 跨域

JSONP 是利用浏览器对 <script> 的资源引用没有同源限制这一特点来实现跨域请求。其原理是浏览器端动态生成 <script> 标签来请求后台提供数据的接口,并定义好用于接收响应数据的函数,同时将函数名通过请求参数提交给后台。服务器端接收到请求处理产生结果数据后,返回一个函数调用的 js 代码,并将结果数据作为实参传入到回调函数中。浏览器端收到响应后自动执行函数调用的 js 代码,即执行了提前定义好的回调函数,便得到了所需要的结果数据。

优点是对浏览器的支持较好,尤其支持老式浏览器。缺点是只能解决 GET 类型的 ajax 跨域请求,其他类型的跨域请求并不能处理;错误处理机制并不完善,无法进行错误处理。

前后端配合的代码示例:

前端 AJAX 请求:

$.ajax({
    url: "http://otherdomain.com/manage/role/get",
    async: false,
    type: "get",
    dataType: "jsonp",
    data: {
        "id": 1
    },
    jsonp: "callback",
    jsonpCallback:"fn",
    success: function(data){
        alert(data.code);
    },
    error: function(){
        alert('fail');
    }
})


后端响应数据:

@RequestMapping("/manage/role/get")
@ResponseBody
public String get(HttpServletRequest request, HttpServletResponse response) {
    BaseOutput outPut = new BaseOutput();
    try {
        QueryFilter filter = new QueryFilter(request);
        logger.info(filter.toString());
        String id = filter.getParam().get(MainConst.KEY_ID);
        if(!StringUtil.isEmpty(id)) {
            ImRole role = roleService.getByPk(filter);
            outPut.setData(role);
        } else {
            outPut.setCode(OutputCodeConst.INPUT_PARAM_IS_NOT_FULL);
            outPut.setMsg("The get id is needed.");
        }
    } catch (Exception e) {
        logger.error("获取角色数据异常!", e);
        outPut.setCode(OutputCodeConst.UNKNOWN_ERROR);
        outPut.setMsg("获取角色数据异常! " + e.getMessage());
    }
    return "fn("+JsonUtil.objectToJson(outPut)+")";
}

(二)nginx 反向代理

nginx 反向代理解决跨域的原理是将 nginx 安装在本地,将项目部署于 nginx 下,通过反向代理的方式访问后台服务器。当浏览器发起请求时,由于请求的域名、协议、端口与 nginx 服务器相同,满足同源策略,从而避免了跨域问题。

需要进行的额外配置情况如下:

  1. 下载并安装 nginx。
  1. 在 nginx.conf 文件中进行配置,例如配置本地 web 项目访问路径和反向代理。
server {
    listen       80;
    server_name  localhost;
    location/ {
        root   myApp/mobile;
        index index.html index.htm;
    }
    location/remote-interface/{
        proxy_pass  http://remote-address/remote-interface/ ;
    }
}


(三)PHP 端修改 header

通过 PHP 端修改 header 可以解决跨域问题。可以在文件 header 里设置 ACCESS-CONTROL-ALLOW-ORIGIN,允许特定域名或所有域名访问。

设置方式如下:

  1. 允许全部的域名访问
header("Access-Control-Allow-Origin:*");
  1. 允许指定域名访问
header('Access-Control-Allow-Origin:http://a.test.com');

(四)document.domain 跨子域

利用 document.domain 可以解决不同域的两个页面之间 JavaScript 交互操作限制。此方案仅限于跨子域的应用场景,两个页面通过设置 document.domain 为基础主域,从而实现同域。

例如:

// A 页面:http://www.example.com/a.html
// B 页面:http://example.com/b.html
// 当 A、B 想要获取对方的 cookie 或者 DOM 节点时,可以设置:
document.domain='example.com';

(五)CORS 跨域

CORS(Cross-Origin Resource Sharing),即跨域资源共享。其原理是利用浏览器自动添加一些附加的头信息来实现跨域请求。服务器端通过返回特定的响应头来控制是否同意跨域请求。

服务器端响应头设置:

  1. 指定允许其他域名访问
Access-Control-Allow-Origin:// 值要么是请求时 Origin 字段的值,要么是一个 *,表示接受任意
域名的请求。
  1. 是否允许后续请求携带认证信息(cookies)
Access-Control-Allow-Credentials:true // 值是一个布尔值,表示是否允许发送 Cookie。
  1. 预检结果缓存时间
Access-Control-Max-Age: 1800
  1. 允许的请求类型
Access-Control-Allow-Methods:GET,POST,PUT,POST
  1. 允许的请求头字段
Access-Control-Allow-Headers:x-requested-with,content-type

如果要在跨域请求中带上 cookie,需要满足 3 个条件:

  1. web(浏览器)请求设置 withCredentials 为 true。
  1. 服务器设置首部字段 Access-Control-Allow-Credentials 为 true。
  1. 服务器的 Access-Control-Allow-Origin 不能为 *。

(六)图片 ping 或 script 标签跨域

图片 ping 和 script 标签跨域的方式是利用浏览器允许加载不同源的图片和脚本的特点来实现跨域数据传递。特点是简单易用,但缺点是只能进行单向的数据传递,且无法获取响应内容。

(七)window.name + iframe

通过 window.name 和 iframe 结合实现跨域的原理是在页面中动态创建一个 iframe 页面指向另一个域,将数据赋值给 iframe 的 window.name 属性,然后将 iframe 的 src 指向相同域的空白页面,之后再将 iframe 删除,就可以在当前页面获取到跨域的数据。

代码实现过程:

var proxy = function(url, callback) {
    var state = 0;
    var iframe = document.createElement('iframe');
    iframe.src = url;
    iframe.onload = function() {
        if (state ===1) {
            callback(iframe.contentWindow.name);
            destoryFrame();
        } else if (state ===0) {
            iframe.contentWindow.location = 'http://www.domain.com/aa.html';
            state = 1;
        }
    };
    document.body.appendChild(iframe);
};


(八)postMessage

postMessage 是 HTML5 XMLHttpRequest Level 2 中的 API,它可以用于不同窗口之间的消息传递,包括跨域数据传递。

原理是通过 postMessage(data, origin) 方法,接受两个参数:data(要发送的数据,可以是任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用 JSON.stringify() 序列化)和 origin(协议 + 域名 + 端口号,也可以设置为 "*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话,设置为 "/")。

例如:

在父页面中嵌入子页面,通过 postMessage 发送数据。

// parent.com/index.html
window.onload = function() {
    var ifr = document.getElementById('ifr');
    var targetOrigin = 'http://child.com';
    ifr.contentWindow.postMessage('I was there!', targetOrigin);
};

在子页面中通过 message 事件监听父页面发送来的消息并显示。

// child.com/index.html
window.addEventListener('message', function(event){
    if (event.origin == 'http://parent.com') {
        alert(event.data);
        alert(event.source);
    }, false);
};

(九)websocket

websocket 作为跨域解决方案的原理是通过建立一个持久化的连接,使得客户端和服务器可以双向通信,不受同源策略的限制。

代码实现如下:

var socket = new WebSocket('ws://otherdomain.com/socket');
socket.onopen = function() {
    socket.send('Hello from client!');
};
socket.onmessage = function(event) {
    console.log('Received message from server: ' + event.data);
};

(十)Node 中间件代理

Node 中间件代理解决跨域的原理是在 Node.js 服务器端设置一个代理,将客户端的请求转发到目标服务器,然后将目标服务器的响应返回给客户端。这样,对于客户端来说,请求看起来就像是来自同一个域。

代码示例:

const express = require('express');
const request = require('request');

const app = express();

app.use('/proxy', function(req, res) {
    request('http://otherdomain.com' + req.url).pipe(res);
});

app.listen(3000, function() {
    console.log('Proxy server running on port 3000');
});

(十一)nginx 反向代理

再次强调 nginx 反向代理解决跨域的原理是通过将本地的请求转发到不同域的服务器上,同时满足浏览器的同源策略,从而避免跨域问题。其优势在于配置相对简单,不需要对前端代码进行大量修改,并且可以同时代理多个不同域的服务器。

扫描二维码推送至手机访问。

版权声明:本文由AR编程网发布,如需转载请注明出处。

本文链接:http://www.arlanguage.com/post/477.html

分享给朋友:

“深入理解跨域及跨域请求数据方式” 的相关文章

Nginx 高可用方案

原文链接:https://www.cnblogs.com/SimpleWu/p/11004902.html准备工作192.168.16.128192.168.16.129两台虚拟机。安装好Nginx安装Nginx更新yum源文件:rpm -ivh http://nginx.org/packages/...

轻松搭建基于 Serverless 的 ThinkPHP 应用

ThinkPHP 是什么?ThinkPHP 是一个免费开源的,快速、简单的面向对象的轻量级 PHP 开发框架,是为了敏捷 WEB 应用开发和简化企业应用开发而诞生的。ThinkPHP 从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简代码的同时,更注重易用性。遵循 Apache2 开源许可...

如何在本地部署WEB开发(PHP)环境

目前很多网站程序是基于PHP语言,比如比较有名的开源程序WordPress、Discuz、DedeCMS...对于大多初学者来说,本地部署WEB环境(PHP/ASP+Apache/Nginx+Mysql),一个一个安装调试是一件很麻烦的事。所以这次分享一下如何在本地快速搭建WEB环境!考虑到大家大多...

php高并发的瓶颈到底在哪

php高并发的瓶颈到底在哪?是同步阻塞?还是nginx+fpm不断创建-销毁进程资源过度消耗?高并发到底是什么问题,是语言问题嘛,为什么说php不适合高并发?求大佬指点从2009年后一直用lnmp,从5.2.17一直到现在的PHP7.4,做的项目无数个,大到日IP10W+、PV50W+的平台,小到日...

Nginx如何配置正向代理:一步步教你轻松上手

Nginx作为一个高性能的HTTP和反向代理服务器,广泛应用于各类网站和服务中。然而,很多人可能不知道,Nginx同样可以配置为正向代理。今天我们就来详细讲解一下如何配置Nginx作为正向代理,让你的网络访问更加灵活便捷。什么是正向代理?正向代理是指客户端通过代理服务器访问目标服务器的过程。简单来说...

一般人绝对无法发现的nginx锅

nginx热启动:nginx -s reloadPS:要在/etc/profile环境变量PATH里配置nginx的路径。配置完执行 source /etc/profile 让变量生效。 一次部署,同样的前端代码,放到了nginx里面运行,但是有一个模块全部页面都报这个错误,其他模块正常展示。以前遇...