跨域请求问题

跨域问题

概述

在 HTML 中,<a>, <form>, <img>, <script>, <iframe>, <link> 等标签以及 Ajax 都可以指向一个资源地址,而所谓的跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指的是这样的一个概念:我们认为若协议 + 域名 + 端口号均相同,那么就是同域。

举个栗子,比如当前网址是www.test.com,而我想访问images.test.com,那么这就算是跨域请求了(域名不同);又或者在www.test.com:8080这个网址去访问www.test.com:8081,那么这也是跨域请求(端口号不同);又比如在http://www.test.com去访问https://www.test.com,那么这个也是跨域请求(协议不同)。

跨域缘由

主要源自浏览器制定的同源策略(Same origin policy),何为同源策略?所谓同源就是指上面提到的"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。

跨域的后果

由于同源策略造成的跨域有什么结果呢?一般会有下面几种限制:

  1. Cookie、LocalStorage 和 IndexDB 无法读取
  2. DOM 和 Js对象无法获得
  3. AJAX 请求不能发送(实际是请求能发送过去,但是结果拿不到,会被拦截下来)

问题解决方案

JSONP

前端页面示例
原生JS实现
<body>
  <input type="text" id="msg"> <br />
  <input type="button" value="加载" onclick="loadData()" />
</body>

<script type="text/javascript">

function setVal(data) {
    console.log(data);
    $("#msg").val(data);
}

function loadData() {
    var script = $("<script>");
    script.attr("src", "http://localhost:8081/loadData?callback=setVal");
    script.attr("type", "text/javascript");
    $("head").append(script);
}
</script>
jQuery实现
<body>
  <input type="text" id="msg"> <br />
  <input type="button" value="加载" onclick="loadData()" />
</body>

<script type="text/javascript">

function setVal(data) {
    console.log(data);
    $("#msg").val(data);
}

function loadData() {
    $.ajax({
        url: 'http://localhost:8080/loadData',
        type: 'get',
        dataType: 'jsonp',  // 请求方式为jsonp
        jsonpCallback: "setVal",    // 自定义回调函数名
        data: {}
    });
}
</script>
后端示例
原始servlet的Java代码
/**
 * 通过处理JSONP请求,解决跨域问题
 */
@WebServlet("/loadData")
public class TestServlet3 extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      String msg = "Hello JSONP";
      String callbackFn = req.getParameter("callback");
      msg = callbackFn + "('" + msg + "');";
      resp.getWriter().println(msg);
   }
}
基于Spring MVC的Java代码
@RequestMapping("/loadData")
@ResponseBody
public Object loadData(String callback) {
   String msg = "Hello JSONP";
   MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(msg);
   mappingJacksonValue.setJsonpFunction(callback);
   return mappingJacksonValue;
}

注: 仅Spring4.x系列支持,5.1以后删除了

通过@CrossOrigin注解实现

这种方式是纯粹的Java后台实现的跨域,前端页面可以照常使用Ajax请求

前端页面

照常发送Ajax请求就行

  <body>
    <input type="text" id="msg"> <br />
    <input type="button" value="加载" onclick="loadData()" />
  </body>
<script type="text/javascript">
  function loadData() {
      var url = "http://localhost:8080/loadData";
      $.get(url, function (data) {
        console.log(data);
        $("#msg").val(data);
      });
  }
</script>
后台代码

这种方式就只能依靠spring的强大能力了,使用spring mvc提供的@CrossOrigin注解就能轻松解决

**注:**这要求你的spring必须是5.x系列才能使用!!!!

@RequestMapping("/loadData")
@ResponseBody
@CrossOrigin
public Object loadData() {
   String msg = "Hello JSONP";
   return msg;
}

也可以添加参数,进一步限制允许跨域请求的范围:

@RequestMapping("/loadData")
@ResponseBody
@CrossOrigin(origins = "http://localhost:8080", methods = {RequestMethod.POST, RequestMethod.GET})
public Object loadData() {
   String msg = "Hello JSONP";
   return msg;
}

@CrossOrigin不仅支持在方法上添加,还支持在Controller类上添加,代表该Controller下面所有方法都支持跨域请求。

实际上底层的实现原理就是通过添加以下响应头实现的:

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

当然这种是所有的跨域请求都放行,不是很安全,如果你需要只让某些网络访问,那么可以将*替换为具体的请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值