我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JS跨域前后端怎么实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JS跨域前后端怎么实现

这篇文章主要介绍“JS跨域前后端怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“JS跨域前后端怎么实现”文章能帮助大家解决问题。

浏览器的同源安全策略

同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。
同源:协议 + 域名 + 端口。所以,怎么才算跨域呢?

什么是跨域

什么是跨域,简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。更详细的说明可以看下表:

URL说明是否允许通信
http://www.a.com/a.js
http://www.a.com/b.js
同一域名下允许
http://www.a.com/lab/a.js
http://www.a.com/script/b.js
同一域名下不同文件夹允许
http://www.a.com:8000/a.js
http://www.a.com/b.js
同一域名,不同端口不允许
http://www.a.com/a.js
https://www.a.com/b.js
同一域名,不同协议不允许
http://www.a.com/a.js
http://70.32.92.74/b.js
域名和域名对应ip不允许
http://www.a.com/a.js
http://script.a.com/b.js
主域相同,子域不同不允许
http://www.a.com/a.js
http://a.com/b.js
同一域名,不同二级域名(同上)不允许(cookie这种情况下也不允许访问)
//www.yisu.com/a.js
http://www.a.com/b.js
不同域名不允许

特别注意两点:

第一,如果是协议和端口造成的跨域问题“前台”是无能为力的,

第二:在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。
“URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”。

一、前端跨域解决方法(JavaScript)

接下来简单地总结一下在“前台”一般处理跨域的办法

1、document.domain+iframe的设置

对于主域相同而子域不同的例子,可以通过设置document.domain的办法来解决。具体的做法是可以在http://www.a.com/a.html和http://script.a.com/b.html两个文件中分别加上document.domain = ‘a.com’;然后通过a.html文件中创建一个iframe,去控制iframe的contentDocument,这样两个js文件之间就可以“交互”了。当然这种办法只能解决主域相同而二级域名不同的情况,如果你异想天开的把script.a.com的domian设为alibaba.com那显然是会报错地!代码如下:

www.a.com上的a.html

document.domain = 'a.com';var ifr = document.createElement('iframe');ifr.class="lazy" data-src = 'http://script.a.com/b.html';ifr.style.display = 'none';document.body.appendChild(ifr);ifr.onload = function(){    var doc = ifr.contentDocument || ifr.contentWindow.document;    // 在这里操纵b.html    alert(doc.getElementsByTagName("h2")[0].childNodes[0].nodeValue);};

script.a.com上的b.html

document.domain = 'a.com';

这种方式适用于{www.jb51.com, jb51.com, script.jb51.com, css.jb51.com}中的任何页面相互通信。

备注:某一页面的domain默认等于window.location.hostname。主域名是不带www的域名,例如a.com,主域名前面带前缀的通常都为二级域名或多级域名,例如www.a.com其实是二级域名。 domain只能设置为主域名,不可以在b.a.com中将domain设置为c.a.com。

问题:

安全性,当一个站点(b.a.com)被攻击后,另一个站点(c.a.com)会引起安全漏洞。

如果一个页面中引入多个iframe,要想能够操作所有iframe,必须都得设置相同domain。

2、动态创建script

虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的JS文件,并可以自由执行引入的JS文件中的function(包括操作cookie、Dom等等)。根据这一点,可以方便地通过创建script节点的方法来实现完全跨域的通信。

这里判断script节点加载完毕还是蛮有意思的:ie只能通过script的readystatechange属性,其它浏览器是script的load事件。以下是部分判断script加载完毕的方法。

js.onload = js.onreadystatechange = function() {    if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {        // callback在此处执行        js.onload = js.onreadystatechange = null;    }};

3、利用iframe和location.hash

这个办法比较绕,但是可以解决完全跨域情况下的脚步置换问题。原理是利用location.hash来进行传值。在url: http://a.com#helloword中的‘#helloworld’就是location.hash,改变hash并不会导致页面刷新,所以可以利用hash值来进行数据传递,当然数据容量是有限的。假设域名a.com下的文件cs1.html要和jb51.net域名下的cs2.html传递信息,cs1.html首先创建自动创建一个隐藏的iframe,iframe的class="lazy" data-src指向jb51.net域名下的cs2.html页面,这时的hash值可以做参数传递用。cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据(由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe;Firefox可以修改)。同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一点有变化则获取获取hash值。代码如下:

先是a.com下的文件cs1.html文件:

function startRequest(){    var ifr = document.createElement('iframe');    ifr.style.display = 'none';    ifr.class="lazy" data-src = '//www.yisu.com/lab/cscript/cs2.html#paramdo';    document.body.appendChild(ifr);}function checkHash() {    try {        var data = location.hash ? location.hash.substring(1) : '';        if (console.log) {            console.log('Now the data is '+data);        }    } catch(e) {};}setInterval(checkHash, 2000);

jb51.net域名下的cs2.html:

//模拟一个简单的参数处理操作switch(location.hash){    case '#paramdo':        callBack();        break;    case '#paramset':        //do something……        break;}function callBack(){    try {        parent.location.hash = 'somedata';    } catch (e) {        // ie、chrome的安全机制无法修改parent.location.hash,        // 所以要利用一个中间的cnblogs域下的代理iframe        var ifrproxy = document.createElement('iframe');        ifrproxy.style.display = 'none';        ifrproxy.class="lazy" data-src = 'http://a.com/test/cscript/cs3.html#somedata';    // 注意该文件在"a.com"域下        document.body.appendChild(ifrproxy);    }}

a.com下的域名cs3.html

//因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值parent.parent.location.hash = self.location.hash.substring(1);

当然这样做也存在很多缺点,诸如数据直接暴露在了url中,数据容量和类型都有限等……

4、window.name实现的跨域数据传输

文章较长列在此处不便于阅读,详细请看 window.name实现的跨域数据传输。

5、使用HTML5 postMessage

HTML5中最酷的新功能之一就是 跨文档消息传输Cross Document Messaging。下一代浏览器都将支持这个功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递。

otherWindow.postMessage(message, targetOrigin);

otherWindow: 对接收信息页面的window的引用。可以是页面中iframe的contentWindow属性;window.open的返回值;通过name或下标从window.frames取到的值。
message: 所要发送的数据,string类型。
targetOrigin: 用于限制otherWindow,“*”表示不作限制

a.com/index.html中的代码:

<iframe id="ifr" class="lazy" data-src="b.com/index.html"></iframe><script type="text/javascript">window.onload = function() {    var ifr = document.getElementById('ifr');    var targetOrigin = 'http://b.com';  // 若写成'http://b.com/c/proxy.html'效果一样                                        // 若写成'http://c.com'就不会执行postMessage了    ifr.contentWindow.postMessage('I was there!', targetOrigin);};</script>

b.com/index.html中的代码:

<script type="text/javascript">    window.addEventListener('message', function(event){        // 通过origin属性判断消息来源地址        if (event.origin == 'http://a.com') {            alert(event.data);    // 弹出"I was there!"            alert(event.source);  // 对a.com、index.html中window对象的引用                                  // 但由于同源策略,这里event.source不可以访问window对象        }    }, false);</script>

二、后台跨域解决方案

CORS

这是W3C的标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

//指定允许其他域名访问‘Access-Control-Allow-Origin:http://172.20.0.206'//一般用法(,指定域,动态设置),3是因为不允许携带认证头和cookies//是否允许后续请求携带认证信息(cookies),该值只能是true,否则不返回‘Access-Control-Allow-Credentials:true'

上面第一行说到的Access-Control-Allow-Origin有多种设置方法:

设置是最简单粗暴的,但是服务器出于安全考虑,肯定不会这么干,而且,如果是的话,游览器将不会发送cookies,即使你的XHR设置了withCredentials
指定域,如上图中的http://172.20.0.206,一般的系统中间都有一个nginx,所以推荐这种
动态设置为请求域,多人协作时,多个前端对接一个后台,这样很方便。
Response支持跨域
从上面控制台的输出可以看到,错误原因是请求的资源(接口)的header中没有”Access-Control-Allow-Origin“,那我们可以给它加上。在哪加?既然说是请求的资源没有,那当然是在请求的资源上加,也就是服务端。

@SpringBootApplication@Configuration@RestControllerpublic class ApplicationA {    public static void main(String[] args) {        SpringApplication.run(ApplicationA.class, args);    }    @RequestMapping("/test")    public Object test(HttpServletRequest request, HttpServletResponse response) {        // 跨域支持        response.setHeader("Access-Control-Allow-Origin", "*");        response.setHeader("Access-Control-Allow-Methods", "POST,GET,PUT,DELETE");        response.setHeader("Access-Control-Max-Age", "3600");        response.setHeader("Access-Control-Allow-Headers", "*");        response.setHeader("Access-Control-Allow-Credentials", "true");        Map<String, Object> map = new HashMap<>();        map.put("success", true);        map.put("msg", "我来自服务端");        return map;    }}

springboot支持跨域

测试用例是一个springboot项目,可以用更简单的方式。通过一个继承了WebMvcConfigurerAdapter的bean,重写addCorsMappings方法,在方法里配置。

@SpringBootApplication@Configuration@RestControllerpublic class ApplicationA extends WebMvcConfigurerAdapter {    public static void main(String[] args) {        SpringApplication.run(ApplicationA.class, args);    }    @RequestMapping("/test")    public Object test(HttpServletRequest request, HttpServletResponse response) {        Map<String, Object> map = new HashMap<>();        map.put("success", true);        map.put("msg", "我来自服务端");        return map;    }    // 跨域支持    @Override    public void addCorsMappings(CorsRegistry registry) {        registry.addMapping("/**")                .allowedOrigins("*")                .allowCredentials(true)                .allowedMethods("GET", "POST", "DELETE", "PUT")                .maxAge(3600);    }

Java中设置多个Access-Control-Allow-Origin跨域访问

如果服务端是Java开发的,添加如下设置允许跨域即可,但是这样做是允许所有域名都可以访问,不够安全。
response.setHeader(“Access-Control-Allow-Origin”,"*");

为保证安全性,可以只添加部分域名允许访问,添加位置可以在下面三处任选一个。
(1)可以在过滤器的filter的dofilter()方法种设置。
(2)可以在servlet的get或者post方法里面设置。
(3)可以放在访问的jsp页面第一行。

在此用第一种方法,注意web.xml配置过滤器(filter)。

public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {        // 将ServletResponse转换为HttpServletResponse        HttpServletResponse httpResponse = (HttpServletResponse) res;        // 如果不是80端口,需要将端口加上,如果是集群,则用Nginx的地址,同理不是80端口要加上端口String []  allowDomain= {"http://www.baidu.com","http://123.456.789.10","http://123.16.12.23:8080"};Set allowedOrigins= new HashSet(Arrays.asList(allowDomain));String originHeader=((HttpServletRequest) req).getHeader("Origin");if (allowedOrigins.contains(originHeader)){    httpResponse.setHeader("Access-Control-Allow-Origin", originHeader);            httpResponse.setContentType("application/json;charset=UTF-8");            httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");            httpResponse.setHeader("Access-Control-Max-Age", "3600");            httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token");            // 如果要把Cookie发到服务器,需要指定Access-Control-Allow-Credentials字段为true            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");                                            httpResponse.setHeader("Access-Control-Expose-Headers", "*");                }                chain.doFilter(req, res);}

基于nginx配置请求的CORS

目前很多请求都不是直接暴露的,很多通过nginx做反向代理,因此可以使用nginx配置固定请求的Access-Control-Allow-Origin,实现跨域访问。方式是在被请求的接口,配置location代理,添加header实现。

        #活动访问接口跨域配置        location /promotion/activityPro {            proxy_pass http://frontHost/promotion/activityPro;            add_header 'Access-Control-Allow-Origin' '*';            #add_header 'Access-Control-Allow-Methods' 'GET, POST';            #add_header 'Access-Control-Allow-Credentials' "true";            #add_header 'Access-Control-Max-Age' 86400;            #add_header 'Access-Control-Allow-Header' 'Content-Type,*';        }

三、前端跨域JSONP方案

有前端经验的童鞋知道,有时我们会在自己的代码里直接引入其它域名的js、css等静态文件。为啥这些静态文件没被浏览器限制呢?通常为了减轻web服务器的压力,我们会把js、css,img等静态资源分离到另一台独立域名的服务器上,使其和前端分离开。基于这个原因,浏览器并没有限制这类静态资源的跨域访问。

我们可以动态地创建一个script,让浏览器以为我们要获取静态资源,从而网开一面。而服务器端也需要做一点改变,不能直接返回json,而是返回一个立即执行的函数,而前端请求的结果就作为函数的参数。

后端接口返回

@SpringBootApplication@Configuration@RestControllerpublic class ApplicationA {    public static void main(String[] args) {        SpringApplication.run(ApplicationA.class, args);    }    @RequestMapping("/test")    public String test(HttpServletRequest request, HttpServletResponse response, String callback)            throws IOException {        Map<String, Object> map = new HashMap<>();        map.put("success", true);        map.put("msg", "我来自服务端");        // 返回值如下:        // callback({"msg":"我来自服务端","success":true});        return String.format("%s(%s);", callback, JsonUtil.toJson(map));    }

js原生实现jsonp

function test() {    // 外部域名,参数是和后端接口约定的callback指定接口返回后的回调函数    url = "http://localhost:8882/test?callback=_ajax_callback";    // 创建一个script元素    var script = document.createElement('script');    script.type = 'text/javascript';    script.class="lazy" data-src = url;    document.head.appendChild(script);}// 接口回调function _ajax_callback(res) {    console.log("被回调了");    console.log(res);}

jQuery实现jsonp

$.ajax({    url: 'http://localhost:8882/test',    type: 'get',    dataType: 'jsonp',  // 请求方式    jsonpCallback: "_ajax_callback",    // 回调函数名    data: {}});

vue.js实现jsonp

this.$http.jsonp(‘http://localhost:8882/test', {undefinedparams: {},jsonp: ‘_ajax_callback'}).then((res) => {undefinedconsole.log(res);})

JSONP的优缺点

优点:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。

缺点:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。

其它方式支持跨域
nginx反向代理:前端访问相同域名,nginx再根据需要把请求转发到外部域名;
后端代理:在后端接口里先请求外部资源(比如用HttpClient),然后把结果返回给前端,这样就不是跨域了;
其它:借助iframe、postMessage等也可实现跨域。
document.domain,window.name,web sockets

关于“JS跨域前后端怎么实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网行业资讯频道,小编每天都会为大家更新不同的知识点。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JS跨域前后端怎么实现

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

JS跨域前后端怎么实现

这篇文章主要介绍“JS跨域前后端怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“JS跨域前后端怎么实现”文章能帮助大家解决问题。浏览器的同源安全策略同源策略,它是由Netscape提出的一个著
2023-06-29

js实现前端跨域postMessage的具体使用

这篇文章主要介绍了js实现前端跨域postMessage的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-05-17

vue前后端分离如何实现单点登录跨域

这篇文章主要介绍“vue前后端分离如何实现单点登录跨域”,在日常操作中,相信很多人在vue前后端分离如何实现单点登录跨域问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”vue前后端分离如何实现单点登录跨域”的疑
2023-07-04

springboot怎么解决前后端分离时的跨域问题

这篇文章主要介绍springboot怎么解决前后端分离时的跨域问题,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!springboot是什么springboot一种全新的编程规范,其设计目的是用来简化新Spring应用
2023-06-14

跨域浏览器怎么设置解决前端跨域问题

这篇文章主要介绍“跨域浏览器怎么设置解决前端跨域问题”,在日常操作中,相信很多人在跨域浏览器怎么设置解决前端跨域问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”跨域浏览器怎么设置解决前端跨域问题”的疑惑有所
2023-07-02

web前端跨域问题怎么解决

本文小编为大家详细介绍“web前端跨域问题怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“web前端跨域问题怎么解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。为什么跨域?为什么会出现跨域问题呢?那就不
2023-06-29

java后端怎么解决跨域问题

在Java后端解决跨域问题可以使用以下几种方法:使用Servlet的过滤器:创建一个实现javax.servlet.Filter接口的过滤器,在过滤器中设置响应头信息Access-Control-Allow-Origin为允许访问的域名。然
2023-10-23

spring boot配合前端实现跨域请求访问

一.方法: 服务端设置Respone Header头中Access-Control-Allow-Origin 配合前台使用jsonp 继承WebMvcConfigurerAdapter 添加配置类 二.实例:1.前端:因为我们用了前
2023-05-31

django前后端分离怎么实现

要实现Django的前后端分离,可以使用Django Rest Framework(DRF)作为后端框架,同时使用一个前端框架(如React、Vue.js)来处理前端的界面和交互逻辑。下面是一个简单的实现步骤:1. 在Django项目中安装
2023-10-09

SpringSecurity怎么实现前后端分离

今天小编给大家分享一下SpringSecurity怎么实现前后端分离的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Sprin
2023-07-05

如何去解决JS跨域问题 怎么能学好Web前端开发

如何去解决JS跨域问题?怎么能学好Web前端开发?JavaScript跨域是指通过JS在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过JS获取页面中不同域的框架中(iframe)的数据。只要协议、域名、端口有
2023-06-03

nodeJS(express4.x)+vue(vue-cli)构建前后端分离实例(带跨域)

准备工作: 1.安装nodejs ---还用我教了?2.安装依赖包express4.x 点这里》》》nodeJS搭建本地服务器3.安装vue-cli脚手架 点这里》》》vue-cli构建vue项目 这里强调一下,express是后端服务器
2022-06-04

如何实现nginx前后端同域名配置

小编给大家分享一下如何实现nginx前后端同域名配置,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!nginx前后端同域名配置的方法实现,具体如下:upstream
2023-06-14

java项目中使用Cors实现后端跨域的法

今天就跟大家聊聊有关java项目中使用Cors实现后端跨域的法,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。代码如下:package com.lvluo.web.filter.Cor
2023-05-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录