JavaScript 跨域问题的几种解决方法

一、 前言

二、 版本

编号修改日期版本号修改人修改说明
12017.09.241.0ZZ初稿
12017.12.261.0ZZ完善 CORS + Demo

三、为什么会产生跨域问题

  域名、协议、端口者都相同就是同一个域,否则就是跨域。

  JavaScript出于安全方面的考虑,采取了同源策略,即当前域的客户端脚本不允许在没有明确授权的情况下,读取其他域的资源。如果没有同源策略,那么一旦误执行了恶意网站的js脚本,该js脚本便可以随意获取其他域页面document、session、cookie等信息,很不安全。

  然而我们经常把网站的一些脚本、图片或其他资源放到静态服务器,页面可以更快的加载,而且减少了Web服务器的压力。或者系统间接口调用。这时就产生了跨域问题。

  • eg:console 报错如下(端口不同):
XMLHttpRequest cannot load http://localhost:8888/other/index.jsp. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.

四、如何解决跨域问题

4.1、代理服务器

  一种简单的办法,就是把跨域的工作交给服务器,从后台获取其他站点的数据再返回给前台,也就是跨域代理(Cross Domain Proxy)。这种方法似乎蛮简单的,改动也不太大。不过就是http请求多了些,响应慢了些,服务器的负载重了些。

4.2、通过jQuery实现JSONP的方式实现跨域

JSONP 是 JSON with padding(填充式 JSON 或参数式 JSON)的简写。

JSONP实现跨域请求的原理是动态创建

<html>
    <body>
        <div>
            <button id="btn_jsonp" onclick="jsonp_function()">JSONP点击</button>
        </div>
    </body>

    <script type = "text/javascript">
        function jsonp_function(){
            // $("#btn").click(function() {
                $.ajax({
                    async: true,
                    url: "http://localhost:8080/ApiDemo_Yshow/Student/getStudentList",
                    type: "GET",
                        dataType : "jsonp", // 返回的数据类型,设置为JSONP方式
                        jsonp : 'callback',  // 回调函数名形参 url?callback = call_back
                        jsonpCallback: 'call_back', // 回调函数名实参
                    success: function(data, status) {
                        console.log('状态为:' + status);
                        console.log(data);
                    }
                });
            // });
        }
    </script>
</html>
  • 服务端处理请求:
package com.api.controller;

import org.springframework.beans.factory.annotation.Autowired;
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;

import com.alibaba.fastjson.JSON;
import com.api.common.ListResponse;
import com.api.model.Student;
import com.api.service.StudentService;

@Controller
@RequestMapping("/Student/")
public class StudentController {

    @Autowired
    StudentService studentService;

    @RequestMapping(value = "getStudentList", produces="text/html;charset=UTF-8")
    @ResponseBody
    public String getStudentList(String callback) { // 回调函数名也可以写死
    ListResponse<Student> studentList = studentService.getStudentList();

    return callback+"("+JSON.toJSONString(studentList)+")";
    }
}
  • 服务端返回的数据格式如下:
call_back({
    "items": [
        {
            "age": 21,
            "classes": "173521班",
            "id": 1,
            "name": "张敏",
            "sex": "女"
        },
        {
            "age": 21,
            "classes": "173521班",
            "id": 2,
            "name": "江南",
            "sex": "男"
        }
    ]
})
  • 如上述代码所示jQuery实现jsonp调用的步骤是:
    • 浏览器端定义回调函数作为url参数传送到服务端。url?callback = call_back。
    • 服务端接收到参数后根据参数名+data数据封装成js函数格式的数据返回到浏览器端。
    • 浏览器端接受到数据后执行回调函数,Jquery中为success函数。执行返回的js代码。
    • 从而得到data数据。

JSONP是较为常用的一种跨域方式,不受浏览器兼容性的限制,然而它支持GET请求,RESTful架构并不适用。

4.3、通过CORS实现跨域(推荐)

跨域资源共享(Cross-Origin Resource Sharing)是由W3C提出的一个用于浏览器以XMLHttpRequest方式向其他源的服务器发起请求的规范。不同于JSONP,CORS是以Ajax方式进行跨域请求,需要服务端与客户端的同时支持。目前CORS在绝大部分现代浏览器中都是支持的。

  • 前端ajax请求:
<html>
    <body>
        <div>
            <button id="btn_cors" onclick="CORS_function()">CORS点击</button>
        </div>
    </body>

    <script type = "text/javascript">
        function CORS_function() {
            $.ajax({
                async: true,
                url: "http://localhost:8080/ApiDemo_Yshow/Student/getStudentByName",
                type: "GET",
                dataType: "json",
                data: {
                    "name": "江南天地"
                },
                success: function(data, status) {
                    console.log('状态为:' + status);
                    console.log(data);
                }
            });
        }
    </script>
</html>
  • 服务端处理请求 - 方法1 - setHearder:
package com.api.controller;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.api.common.SingleResponse;
import com.api.service.StudentService;

@Controller
@RequestMapping("/Student/")
public class StudentController {

    @Autowired
    StudentService studentService;

    @RequestMapping(value = "getStudentByName")
    @ResponseBody
    public SingleResponse getStudentByName(@RequestParam(value = "name", required = false) String name,//
        HttpServletResponse response) {
    SingleResponse student = studentService.getStudentByName(name);
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH");
    return student;
    }
}
  • 服务端处理请求 - 方法2 - @CrossOrigin 注释(SpringMVC4.2以上)
package com.api.controller;

import org.springframework.beans.factory.annotation.Autowired;
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;

import com.api.common.SingleResponse;
import com.api.service.StudentService;

@Controller
@RequestMapping("/Student/")
public class StudentController {

    @Autowired
    StudentService studentService;

    @CrossOrigin(origins = "*", maxAge = 3600)
    @RequestMapping(value = "getStudentByName",method = RequestMethod.POST)
    @ResponseBody
    public SingleResponse getStudentByName(String name) {

    SingleResponse student = studentService.getStudentByName(name);
    return student;
    }
}
  • 服务端处理请求-方法3 - 第三方CORSFilter - web.xml
<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
    <init-param>
        <param-name>cors.allowed.origins</param-name>
        <param-value>*</param-value>
    </init-param>
    <init-param>
        <param-name>cors.allowed.methods</param-name>
        <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
    </init-param>
    <init-param>
        <param-name>cors.allowed.headers</param-name>
        <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,自定义header</param-value>
    </init-param>
    <init-param>
        <param-name>cors.exposed.headers</param-name>
        <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
    </init-param>
    <init-param>
        <param-name>cors.support.credentials</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>cors.preflight.maxage</param-name>
        <param-value>10</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

五、参考资料

六、后记

本文仅用于学习笔记记录。初始版本比较粗糙,后续会不断完善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值