跨域问题的超详细全解(附示例)

本篇文章给大家带来的内容是关于跨域问题的超详细全解(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

跨域,老生常谈的问题

简述

作为一只前端菜鸟,跨域方面只懂得JSONP和CORS,并未曾深入了解。但随着春招越来越近,就算是菜鸟也要猛振翅膀。近几日仔细研究了跨域问题,写下这篇文章,希望对开发者们有所帮助。在读本文前,希望您对以下知识略有了解。

浏览器同源策略

nodejs

iframe

docker, nginx

我们为何要研究跨域问题

因为浏览器的同源策略规定某域下的客户端在没明确授权的情况下,不能读写另一个域的资源。而在实际开发中,前后端常常是相互分离的,并且前后端的项目部署也常常不在一个服务器内或者在一个服务器的不同端口下。前端想要获取后端的数据,就必须发起请求,如果不错一些处理,就会受到浏览器同源策略的约束。后端可以收到请求并返回数据,但是前端无法收到数据。

多种跨域方法

跨域可以大概分为两种目的

前后端分离时,前端为了获取后端数据而跨域

为不同域下的前端页面通信而跨域

为前后端分离而跨域

Cross Origin Resource Share (CORS)

CORS是一个跨域资源共享方案,为了解决跨域问题,通过增加一系列请求头和响应头,规范安全地进行跨站数据传输

请求头主要包括

请求头 解释

OriginOrigin头在跨域请求或预先请求中,标明发起跨域请求的源域名。Access-Control-Request-MethodAccess-Control-Request-Method头用于表明跨域请求使用的实际HTTP方法Access-Control-Request-HeadersAccess-Control-Request-Headers用于在预先请求时,告知服务器要发起的跨域请求中会携带的请求头信息

响应头主要包括

响应头 解释

Access-Control-Allow-OriginAccess-Control-Allow-Origin头中携带了服务器端验证后的允许的跨域请求域名,可以是一个具体的域名或是一个*(表示任意域名)。Access-Control-Expose-HeadersAccess-Control-Expose-Headers头用于允许返回给跨域请求的响应头列表,在列表中的响应头的内容,才可以被浏览器访问。Access-Control-Max-AgeAccess-Control-Max-Age用于告知浏览器可以将预先检查请求返回结果缓存的时间,在缓存有效期内,浏览器会使用缓存的预先检查结果判断是否发送跨域请求。Access-Control-Allow-MethodsAccess-Control-Allow-Methods用于告知浏览器可以在实际发送跨域请求时,可以支持的请求方法,可以是一个具体的方法列表或是一个*(表示任意方法)。

如何使用

客户端只需按规范设置请求头。

服务端按规范识别并返回对应响应头,或者安装相应插件,修改相应框架配置文件等。具体视服务端所用的语言和框架而定

SpringBoot 设置CORS例子

一个spring boot项目中关于CORS配置的一段代码

HttpServletResponse httpServletResponse = (HttpServletResponse) response;        String temp = request.getHeader("Origin");        httpServletResponse.setHeader("Access-Control-Allow-Origin", temp);        // 允许的访问方法        httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");//         Access-Control-Max-Age 用于 CORS 相关配置的缓存        httpServletResponse.setHeader("Access-Control-Max-Age", "3600");        httpServletResponse.setHeader("Access-Control-Allow-Headers",                "Origin, X-Requested-With, Content-Type, Accept,token");        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");

登录后复制

JSONP 跨域

jsonp的原理就是借助HTML中的标签可以跨域引入资源。所以动态创建一个标签,src为目的接口 + get数据包 + 处理数据的函数名。后台收到GET请求后解析并返回函数名(数据)给前端,前端标签动态执行处理函数
观察下面代码

前端代码

        Title    var script = document.createElement('script');    script.type = 'text/javascript';    // 传参并指定回调执行函数为getData    script.src = 'http://localhost:8080/users?username=xbc&callback=handleData';    document.body.appendChild(script);    // 回调执行函数    function handleData(res) {        data = JSON.stringify(res)        console.log(data);    }

登录后复制

后端代码(nodejs)

var querystring = require('querystring');var http = require('http');var server = http.createServer();server.on('request', function(req, res) {    var params = querystring.parse(req.url.split('?')[1]);    var fn = params.callback;    // jsonp返回设置    res.writeHead(200, { 'Content-Type': 'text/javascript' });    var data = {        user: 'xbc',        password: '123456'    }    res.write(fn + '(' + JSON.stringify(data) + ')');    res.end();});server.listen('8080');console.log('Server is running at port 8080...');

登录后复制

在该例子中,前台收到的res是这样的

2328813074-5c399a4b60e20_articlex.png

前端页面是这样的

3427611825-5c399a8752e49_articlex.png

注意

JSONP既是利用了,那么就只能支持GET请求。其他请求无法实现

nginx 反向代理实现跨域

思路

既然浏览器有同源策略限制,那我们把前端项目和前端要请求的api接口地址放在同源下不就可以了?再结合web服务器提供的反向代理,便可以在前端和后端都不做配置的情况下解决跨域问题。

以nginx为例

后端真实后台地址:http://xxx.xxx.xxx.xxx:8085 后台地址使用tomcat部署的spring boot项目 名为gsms_test

nginx服务器地址: http://xxx.xxx.xxx.xxx:8082

tomcat和nginx都是用docker架设的,做了端口转发

使用条件:开发环境为linux系统

nginx /etc/nginx/conf.d/default.conf配置代码如下

server {    listen       80;    server_name  localhost;    #charset koi8-r;    #access_log  /var/log/nginx/host.access.log  main;    location / {        # root   /usr/share/nginx/html/dist; # 前端项目路径        # index  index.html index.htm;        proxy_pass http://localhost:8001/; # 前端本机地址,实现自动更新        autoindex on;        autoindex_exact_size on;        autoindex_localtime on;    }    location /gsms_test/ {        proxy_pass 后端真实地址;    }        #error_page  404              /404.html;    # redirect server error pages to the static page /50x.html    #    error_page   500 502 503 504  /50x.html;    location = /50x.html {        root   /usr/share/nginx/html;    }    # proxy the PHP scripts to Apache listening on 127.0.0.1:80    #    #location ~ .php$ {    #    proxy_pass   http://127.0.0.1;    #}    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000    #    #location ~ .php$ {    #    root           html;    #    fastcgi_pass   127.0.0.1:9000;    #    fastcgi_index  index.php;    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;    #    include        fastcgi_params;    #}    # deny access to .htaccess files, if Apache's document root    # concurs with nginx's one    #    #location ~ /.ht {    #    deny  all;    #}}

登录后复制

不同域下页面通信而跨域

window.name + iframe 跨域

window.name是浏览器中一个窗口所共享的数据,在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)。比如 a域的某页面想获取b域某页面的数据,可以在b域中修改window.name值,a域切换到b域再切回来即可得到b域的window.name值。可是我们在开发中肯定不想页面切来切去,所以就要结合iframe来实现。

示例 (以thinkjs实现)

a 域代码如下

A 域

server A

function getData() { var iframe = document.getElementById('proxy'); iframe.onload = function () { var name = iframe.contentWindow.name; // 获取iframe窗口里的window.name值 console.log(name) } // 由于iframe信息传递也受同源策略限制,所以在window.name被B域修改后,将iframe转回A域下。以便获取iframe的window.name值 iframe.src = 'http://127.0.0.1:8360/sub.html' }

登录后复制

b 域代码

New ThinkJS Application  

server 2

window.name = 'user: xbc';

登录后复制

注意

由于受同源策略限制,父页面获取跨域的iframe页面的信息不全,所以要在iframe的window.name被B域修改后,转为A域下的任一页面(该一面不得修改window.name),在进行获取。

代理页面 + iframe 实现跨域访问

由于iframe与父页面相互访问也受同源策略限制,所以要借助一代理页面实现跨域。

91411899-5c39a7740f92f_articlex.png

个人认为有些麻烦,若有兴趣请看前端如何用代理页面解决iframe跨域访问的问题?

总结

以上几种皆是本人用过或测试过的跨域方法,还有postMessage,WebSocket等跨域方法由于从未接触不做说明。在项目中具体使用那些方法还需具体考虑各种问题

情况 方法

只有GET请求JSONP对兼容性及浏览器版本无要求CORS对兼容性及浏览器版本有要求iframe 或 服务器反向代理(linux 环境下开发)

以上就是跨域问题的超详细全解(附示例)的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2605499.html

(0)
上一篇 2025年3月6日 20:03:46
下一篇 2025年3月6日 20:03:51

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • nginx反向代理webSocket配置

    最近在做项目的时候用到了websocket协议,而且是在微信小程序中用到了websocket,微信小程序中使用wss协议的时候不能设置端口,只能使用默认的443端口。我的https已经监听了443端口,websocket再去监听443,肯定…

    2025年3月6日
    200
  • nginx反向代理是什么

    反向代理:是用来代理服务器的,代理我们要访问的目标服务器。代理服务器接受请求,然后将请求转发给内部网络的服务器(集群化),并将从服务器上得到的结果返回给客户端,此时代理服务器对外就表现为一个服务器。 Nginx在反向代理上,提供灵活的功能,…

    2025年3月6日
    200
  • ribbon和nginx的区别

    服务器端负载均衡 nginx nginx 是客户端所有请求统一交给 nginx,由 nginx 进行实现负载均衡请求转发,属于服务器端负载均衡。 既请求由 nginx 服务器端进行转发。 客户端负载均衡 Ribbon Ribbon 是从 e…

    2025年3月6日
    200
  • tomcat有必要加nginx吗

    tomcat既是一个servlet和jsp容器,也是一个轻量级的web服务器,它既可以处理动态内容,也可以处理静态内容。为什么还需要结合nginx一起使用? 原因: (1)、tomcat处理html的能力不如nginx,处理静态内容的速度不…

    2025年3月6日
    200
  • nginx tomcat apache的区别

    apache,指的应该是apache软件基金会下的一个项目——apache http server project; Nginx同样也是一款开源的HTTP服务器软件(当然它也可以作为邮件代理服务器、通用的TCP代理服务器)。 HTTP服务器…

    2025年3月6日
    200
  • 如何实现nginx高可用

    nginx高可用实现方案 一般采用nginx+keepalived,它是一个高性能的服务器高可用或者热备解决方案,Keepalived主要来防止服务器单点故障的发生问题,可以通过其与Nginx的配合实现Web服务器端的高可用; Keepal…

    2025年3月6日
    200
  • Nginx如何解决cookie跨域

    随着项目模块越来越多,很多模块现在都是独立部署。模块之间的交流有时可能会通过cookie来完成。比如说门户和应用,分别部署在不同的机器或者web容器中,假如用户登陆之后会在浏览器客户端写入cookie(记录着用户上下文信息),应用想要获取门…

    2025年3月6日
    200
  • nginx主要做什么

    nginx主要做什么? Nginx 是一个高性能的HTTP和反向代理服务,也是一个IMAP/POP3/SMTP服务。Nginx是由俄罗斯人开发的, Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服…

    2025年3月6日
    200
  • nginx修改配置文件以后怎么重启

    nginx修改配置文件以后怎么重启? 步骤一:nginx经常和tomcat配合使用,nginx的策略配置文件基本都在nginx.conf中,首先登陆Linux服务器,查看我们是否安装nginx服务,如图使用nginx -V命令可以查看我们安…

    2025年3月6日 编程技术
    200
  • nginx负载均衡数据库怎么做

    关于nginx的安装我就不多说了,网上一搜一大把 需要注意的是,nginx在1.9版本之前是只能配置http协议的,不接受tcp协议的代理,所以nginx最常见的功能是服务器的负载均衡配置,大致流程如下:   (推荐学习:nginx教程) …

    2025年3月6日
    200

发表回复

登录后才能评论