实践解决跨域问题的三种方式剖析

最近在做我星际schub网站的时候,遇到了跨域问题,我先把后端node部署在了服务器上,然后在本地localhost测试,出现了问题:

浏览器都提示我们使用这个header头:

解决办法:

1. CORS

服务器设置响应头:

response.setHeader("Access-Control-Allow-Origin", "*")

(这样可能引起CSRF攻击,一般设置成对应的域名就行,
response.setHeader("Access-Control-Allow-Origin", "http:localhost:8080/") )
fetch的option加上 mode:"cors"。

(需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。)
关于CORS的讲解,可以看阮一峰的这篇文章:链接

2.jsonp

jsonp的方式,注意这种方式只能发送get请求,就算指定为post,最后发送的还是get,且跟上面方式一样,也需要服务器的配合支持。之前在做vue音乐播放器项目的时候,调用的是qq音乐的接口,qq音乐的接口返回的就是jsonp格式的

1、 jsonp发送的并不是ajax请求;
2、 利用动态创建一个script标签,因为script标签是没有同源策略限制的,是可以跨域的;
3、 把这个script标签的src指向我们请求的服务端地址,这个地址会携带一个参数:callback ,一个回调函数,服务端会把数据通过这个回调函数返回给客户端,但是客户端没有这个函数怎么接收呢?所以在发送请求之前,要在全局(window)注册这样一个方法,利用这个方法,来获得数据;
4、 这个回调函数名需要跟服务端约定好,是一致的。

如果让我们用原生js实现一个jsonp,那就是这样:

     <script>
         //指定的回调函数
         function showData (result) {
             var data = JSON.stringify(result); //json对象转成字符串
             $("#text").val(data);
         }

         $(document).ready(function () {

             $("#btn").click(function () {
                 //向头部输入一个脚本,该脚本发起一个跨域请求
                 $("head").append("<script src='http://localhost:9090/student?callback=showData'><\/script>");
             });

         });
     </script>

后端一是获取到前端传过来的回调函数名称,二是获取到数据,最后把数据用回调函数包围住,执行这个前端的这个回调函数。我们就可以利用前端这个事先全局注册的回调函数来显示操作数据了。

用Java写的后台demo就是这样:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  response.setCharacterEncoding("UTF-8");
  response.setContentType("text/html;charset=UTF-8");

  //数据
  List<Student> studentList = getStudentList();

  JSONArray jsonArray = JSONArray.fromObject(studentList);
 String result = jsonArray.toString();

 //前端传过来的回调函数名称
 String callback = request.getParameter("callback");
 //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
 result = callback + "(" + result + ")";

 response.getWriter().write(result);
}

这里再分析一下jQuery关于jsonp的实现。

1.最简单的方式:

   $.ajax({
            type:"GET",
            url:"http://www.xxx.com/getMySeat", //访问的链接
            dataType:"jsonp",  //数据格式设置为jsonp
            success:function(data){  //成功的回调函数
                alert(data);
            },
            error: function (e) {
                alert("error");
            }
        });

服务端代码不变,最简单的方式,只需配置一个dataType:‘jsonp‘,就可以发起一个跨域请求。jsonp指定服务器返回的数据类型为jsonp格式,可以看发起的请求路径,自动带了一个callback=xxx,callback是自己不手动设置参数名字的默认值,xxx是jquery随机生成的一个回调函数名称。
这里的success就跟上面的showData一样,如果有success函数则默认success()作为回调函数。

2.回调函数你可以写到script下(默认属于window对象),或者指明写到window对象里,看jquery源码,可以看到jsonp调用回调函数时,是调用的window.callback。
然后看调用结果,发现,请求时带的参数是:callback=showData;调用回调函数的时候,先调用了指定的showData,然后再调用了success。所以,success是返回成功后必定会调用的函数,就看你怎么写了。
指定回调函数名称,加一个option字段即可:

最后还是会调用success:

  1. 如何改变callback这个默认值(回调函数名称的key值),在jq里:

    这样一改之后,响应的后端代码也要改动了,获取的字段key值就是theFunction了,

    对应的请求路径也就变了:

除了jq对jsonp的实现,在上面提到的vue音乐播放器项目中,我使用了jsonp npm包,用这个包,就不需要自己在window上注册回调函数,qq音乐接口中jsonpCallback就是服务端返回的回调函数(a方法) 我们本地在window上注册的a方法是在调用的jsonp库中自动被实现。我们自己写成promise的方法后直接then即可。

但是后来我又遇到一个问题,schub星际网站项目中我想调用WCS职业联赛积分赛排名的接口的时候,用fetch当然还是提示跨域问题了,这时候后端我又不能修改,所以CORS方式肯定不行,jsonp的方式也需要后端配合支持,上面两种方法都不适用了。下面就是最终解决问题的第三种方法。

  1. 代理服务器,跨域问题是浏览器的同源策略限制,服务器之间是没有的,那我们先把请求给我们的代理服务器,再让我们的代理服务器去调用这个接口,在发送给前端就可以了。

前端:

代理服务器(node):

注意服务器返回的数据在response.data里,然后发送给前端的响应res。

4.第四点我想谈下不同跨域方式中关于cookie的。

待续。。。。。

原文地址:https://www.cnblogs.com/zhangmingzhao/p/9302042.html

时间: 2024-07-30 10:11:59

实践解决跨域问题的三种方式剖析的相关文章

jQuery 跨域访问的三种方式 No &#39;Access-Control-Allow-Origin&#39; header is present on the reque

问题: XMLHttpRequest cannot load http://v.xxx.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. test.html:1 Resource interpreted as Script but transferred

服务器端解决跨域问题的三种方法

跨域是指html文件所在的服务器与ajax请求的服务器是不同的ip+port,例如: - ‘192.168.1.1:8080’ 与 ‘192.168.1.2:8080’是不同的域. - ‘192.168.1.1:8080’ 与 ‘192.168.1.1:8081’是不同的域. 解决此类问题的方法很多,有需要客户端和服务端都要更改的,例如jsonp,iframe等等:有只需要客户端更改的,这种情况只能出现在hybrid app开发中,即通过调用native方法来进行网络请求:有只需要服务端配置的,

用jsonp来解决跨域问题的三种简单的方法

jsonp实现跨域的方法 使用ajax方法获取数据不能跨域,为了解决这个问题,普遍使用jsonp来实现跨域,下面是对jsonp方法的简单总结: 例子:假如想获取京东的评论的数据,可以在京东的评论面板打开network找到和ajax请求相关的有回调函数callback的请求url, 如找到一个url, 如: 在响应里可以找到回调函数对应的方法: 这是在服务器上写入的方法用来传输数据. 例如获取到的url为 https://club.jd.com/comment/productPageComment

前端解决跨域问题的8种方案(转)

前端解决跨域问题的8种方案(最新最全) 原文:http://www.cnblogs.com/JChen666/p/3399951.html 1.同源策略如下: URL 说明 是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.jshttp://www.a.com/script/b.js 同一域名下不同文件夹 允许 http://www.a.com:8000/a.jshttp://www

System.Web.Http.Cors配置跨域访问的两种方式

System.Web.Http.Cors配置跨域访问的两种方式 使用System.Web.Http.Cors配置跨域访问,众多大神已经发布了很多文章,我就不在详细描述了,作为小白我只说一下自己的使用心得.在webapi中使用System.Web.Http.Cors配置跨域信息可以有两种方式.  一种是在App_Start.WebApiConfig.cs的Register中配置如下代码,这种方式将在所有的webapi Controller里面起作用. using System; using Sys

前端解决跨域问题的8种方案(最新最全)

原文:http://www.cnblogs.com/JChen666/p/3399951.html 1.同源策略如下: URL 说明 是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.jshttp://www.a.com/script/b.js 同一域名下不同文件夹 允许 http://www.a.com:8000/a.jshttp://www.a.com/b.js 同一域名,不同端

前端解决跨域问题的8种方案(最新最全)(转)

1.同源策略如下: URL说明是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js同一域名下允许 http://www.a.com/lab/a.jshttp://www.a.com/script/b.js同一域名下不同文件夹允许 http://www.a.com:8000/a.jshttp://www.a.com/b.js同一域名,不同端口不允许 http://www.a.com/a.jshttps://www.a.com/b.js同一域名,不同协议

前端解决跨域问题的8种方案

原文http://blog.csdn.net/joyhen/article/details/21631833 1.同源策略如下: URL 说明 是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.jshttp://www.a.com/script/b.js 同一域名下不同文件夹 允许 http://www.a.com:8000/a.jshttp://www.a.com/b.js 同一域

(转)前端解决跨域问题的8种方案(最新最全)

转:http://www.cnblogs.com/JChen666/p/3399951.html 1.同源策略如下: URL 说明 是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.jshttp://www.a.com/script/b.js 同一域名下不同文件夹 允许 http://www.a.com:8000/a.jshttp://www.a.com/b.js 同一域名,不同端口