A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 张荫 于 2018-1-2 17:49 编辑

大家在学习工作中可能会遇到跨域的问题,而我们用的最多的框架又是springmvc。那么我们就来看下如何使用springmvc解决跨域问题。
再说跨域问题的时候,先来给大家扫扫盲,什么是跨域。
说在前面:
我们大家都知道,我们访问一个网站分为了这么几个部分:协议 + ip + 端口 。比如 https://www.baidu.com/,http://localhost:8080/  我们来先说第一个。
https这个是协议 www.baidu.com 这个是一个域名,但是在网络中会有专门的服务器会把这个域名转换成一个ip。这就是我们说的访问网站的前两部分 大家这个时候可能发现,我们并没有在 https://www.baidu.com/中发现端口号,这是因为这里存在一个默认的端口号。如果使用的是https协议那么这个网站的默认端口号就是443。如果使用的是http协议那么使用的默认端口就是80。


http://www.123.com/index.html 调用 http://www.123.com/server.php (非跨域)

http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)

http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)

http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)

http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)

请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。






下面我就来说下什么是跨域。所谓跨域就是协议或者ip或者端口号有其中一项不同的就叫做跨域。
如果是跨域访问,浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。
为什么会有这种安全限制呢?
For security reasons, browsers prohibit AJAX calls to resources residing outside the current origin. For example, as you’re checking your bank account in one tab, you could have the evil.com website open in another tab. The scripts from evil.com should not be able to make AJAX requests to your bank API (e.g., withdrawing money from your account!) using your credentials.

在spring的文档中给了我们这样的解释:

出于安全原因,浏览器禁止对当前来源之外的资源进行AJAX调用。 例如,当您在一个选项卡中检查您的银行帐户时,您可以在另一个选项卡中打开evil.com网站。 来自evil.com的脚本不应该使用您的凭据向您的银行API发出AJAX请求(例如,从您的帐户中提取资金!)。


那么我们现在了解了什么是跨域,那我们如何解决跨域的问题呢?
方法1:使用jsonp
我们知道,我们可以跨域去加载js文件的内容。而jsonp就是使用了这种方式来实现跨域去请求数据的。
[Java] 纯文本查看 复制代码
package com.zhang.web;


import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class JsonpController {

        /**
         * 跨域使用
         * <p>Title: index</p>
         * <p>Description: </p>
         * @return
         */
        @RequestMapping(value="testjsonp/postjsonpdata", method = RequestMethod.POST)
        @ResponseBody
        public Object postJsonpData(String callback) {
                MappingJacksonValue mappingJacksonValue = new MappingJacksonValue("postjsonpdata");
                //设置回调方法
                mappingJacksonValue.setJsonpFunction(callback);
                return mappingJacksonValue;
        }
        
        /**
         * 跨域使用
         * <p>Title: index</p>
         * <p>Description: </p>
         * @return
         */
        @RequestMapping(value="testjsonp/getjsonpdata", method = RequestMethod.GET)
        @ResponseBody
        public Object getJsonpData(String callback) {
                MappingJacksonValue mappingJacksonValue = new MappingJacksonValue("getjsonpdata");
                //设置回调方法
                mappingJacksonValue.setJsonpFunction(callback);
                return mappingJacksonValue;
        }
        
        /**
         * 跨域使用
         * <p>Title: index</p>
         * <p>Description: 自己拼接返回的数据</p>
         * @return
         */
        @RequestMapping(value="testjsonp/getjsonpdatabystitching", method = RequestMethod.GET)
        @ResponseBody
        public String getJsonpDataByStitching(String callback) {
                String strResult = callback + "('getjsonpdataByStitching')";
                return strResult;
        }
        
        /**
         * 跨域使用
         * <p>Title: index</p>
         * <p>Description: 自己拼接返回的数据</p>
         * @return
         */
        @RequestMapping(value="testjsonp/postjsonpdatabystitching", method = RequestMethod.POST)
        @ResponseBody
        public String postJsonpDataByStitching(String callback) {
                String strResult = callback + "('postjsonpdataByStitching')";
                return strResult;
        }
        
        
}


以上是我们controller层使用了2种方式实现jsonp。
  • 使用手动拼接的方式
  • 使用spring自带的MappingJacksonValue类来实现(这个类在spring4.1+中才有)

下面看下前台如何去写

[JavaScript] 纯文本查看 复制代码
$.ajax({
           type: 'get',
           url: "http://localhost:8080/testjsonp/getjsonpdatabystitching",
           dataType:"jsonp",
          success: function(res){
                  alert(res)
          }
        });

我们需要修改的就是type 和 url
通过实验我们发现使用jsonp只能通过get的方式发送请求。使用post无法实现。如果我们不在@RequestMapping中添加方法的类型时也只能够通过get的方式去请求数据。

方法2:使用@CrossOrigin 注解(这个注解使用须在spring4.2+ jdk8+中使用)
[Java] 纯文本查看 复制代码
package com.zhang.web;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@CrossOrigin(origins = "*", maxAge = 3600)
@Controller
public class IndexController {

        /**
         * 
         * <p>Title: getdata</p>
         * <p>Description: 跨域使用get方法</p>
         * @return
         */
        @RequestMapping(value="testcrossorigin/getdata", method = RequestMethod.GET)
        @ResponseBody
        public String getdata() {
                return "getdata";
        }
        
        /**
         * 
         * <p>Title: postdata</p>
         * <p>Description: 跨域使用post方法</p>
         * @return
         */
        @RequestMapping(value="testcrossorigin/postdata", method = RequestMethod.POST)
        @ResponseBody
        public String postdata() {
                return "postdata";
        }
        
        
        
        /**
         * 
         * <p>Title: postdata</p>
         * <p>Description: 跨域使用 并不加方法直接调用</p>
         * @return
         */
        @RequestMapping(value="testcrossorigin/data")
        @ResponseBody
        public String data() {
                return "data";
        }
        
}

以上是使用@CrossOrigin注解后台的使用方式
前台调用时和普通ajax请求直接调用一样。
[JavaScript] 纯文本查看 复制代码
$.ajax({
           type: 'get',
           url: "http://localhost:8080/testcrossorigin/data",
          success: function(res){
                  alert(res)
          }
        });

经测试 使用@CrossOrigin 注解可以自己定义使用get或者post方法。如果不定义RequestMapping中的method 则只能用get方式访问。

1 个回复

倒序浏览
消灭0回复
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马