天天看点

JavaScript 跨域问题的几种解决方法一、 前言二、 版本三、为什么会产生跨域问题四、如何解决跨域问题五、参考资料六、后记

  • 一 前言
  • 二 版本
  • 三为什么会产生跨域问题
  • 四如何解决跨域问题
    • 1代理服务器
    • 2通过jQuery实现JSONP的方式实现跨域
    • 3通过CORS实现跨域推荐
  • 五参考资料
  • 六后记

一、 前言

二、 版本

编号 修改日期 版本号 修改人 修改说明
1 2017.09.24 1.0 ZZ 初稿
1 2017.12.26 1.0 ZZ 完善 CORS + Demo

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

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

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

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

  • eg:console 报错如下(端口不同):

四、如何解决跨域问题

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": ,
            "classes": "173521班",
            "id": ,
            "name": "张敏",
            "sex": "女"
        },
        {
            "age": ,
            "classes": "173521班",
            "id": ,
            "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 = )
    @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>
           

五、参考资料

  • [x] Jsonp解决ajax跨域问题
  • [x] 跨域资源共享 CORS 详解
  • [x] ajax jsonp跨域乱码解决方案
  • [x] 解决ajax跨域的方法原理详解_cnsd
  • [x] Ajax跨域问题的两种解决方法 _博客园
  • [x] 说说JSON和JSONP,也许你会豁然开朗
  • [x] SpringMVC开启CORS支持
  • [x] java 服务端设置跨域
  • [x] CORS解决ajax跨域问题

六、后记

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

继续阅读