JSONP和CORS跨域

文章详细介绍了CORS和JSONP两种跨域解决方案。JSONP适用于早期浏览器,只支持GET请求,而CORS是现代的W3C标准,支持更多请求类型,但不兼容低版本浏览器。文中提供了JSONP的JavaScript和jQuery实现案例,以及CORS在普通Web项目和Spring项目中的配置示例。
摘要由CSDN通过智能技术生成

一、概述

1、跨域说明

一个域名地址由以下几个部分组成:
http://www.aaa.com:8080/s?ie=UTF-8&wd=SpringBoot

  • 协议:http
  • 域名:子域名www,主域名aaa.com
  • 端口:8080

从一个域名的网页去请求另一个域名的资源时,协议,域名,端口任意不同,都会出现跨域问题。

http://www.aaa.com:8080——>http://www.aaa.com:8080:同域访问
http://www.aaa.com:8080——>http://www.bbb.com:8080:跨域访问

2、实现跨域

corsjsonp都是用于解决跨域问题,当两个页面的协议、域名、端口号中有一个不一致时就存在了跨域,一旦出现跨域,浏览器发送跨域请求后,请求回来的数据都会被浏览器所拦截。

注意:浏览器允许发起跨域请求,但是,跨域请求回来的数据,会被浏览器拦截,无法被页面获取到。

如何实现跨域数据请求?

现下实现跨域数据请求,最主要的两种解决方案分别是 JSONPCORS

  1. JSONP : 出现的早,兼容性好(兼容低版本 IE )。是前端程序员为了解决跨域问题,被迫想出来的一种 临时解决方案,最主要的缺点 是只支持 GET 请求,不支持 POST 请求。
  2. CORS : 出现的较晚,它是 W3C 标准,属于跨域 Ajax 请求的根本解决方案。支持 GETPOST 请 求。缺点 是不兼容某些低版本的浏览器。

二、JSONP简介

1、什么是JSONP

JSONP (JSON with Padding) 是 JSON 的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。

2、JSONP的实现原理

概念:浏览器端通过 <script> 标签的 src 属性,请求服务器上的数据,同时,服务器返回一个函数的调用。这种请求数据的方式叫做 JSONP

3、特点

JSONP 不属于真正的 Ajax 请求,因为它没有使用 XMLHttpRequest 这个对象

JSONP 仅支持 GET 请求,不支持 POST、PUT、DELETE 等请求

三、JSONP跨域

jsonp 就是能够跨域请求数据。

利用 src 可以跨域加载 js 代码。这样就可以取到js的代码,然后,在前端执行js代码即可。

在后端我们只要动态生成js代码就好了。

1、案例一(js实现)

(1)前端代码

利用script标签,加载动态生成的js代码,js会回调相应方法,并且将数据传递给回调方法。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>jsonp实现案例</title>
<script type="text/javascript">
    var flightHandler = function(data){
        alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
    };
    // 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
    var url = "http://ip/WxServlet/jsonp2.js?callback=flightHandler";
    // 创建script标签,设置其属性
    var script = document.createElement('script');
    script.setAttribute('src', url);
    // 把script标签加入head,此时调用开始
    document.getElementsByTagName('head')[0].appendChild(script);
</script>
</head>
<body>
</body>
</html>

(2)后端代码

动态生成js代码,代码里放置一个回调方法。

String code = req.getParameter("code");
String collback = req.getParameter("callback");
System.out.println(code+collback);
String str = "flightHandler({\"code\": \"CA1998\",\"price\": 1780,\"tickets\": 5});";
resp.getWriter().append(str);

2、案例二(jquery实现)

(1)前端代码

接下来看下使用jquery的jsonp来实现跨域访问,例子如下:

$(function(){  
    $.ajax({  
        type: "get",  
        async: false,  
        url: "http://ip/WxServlet/jsonp2.js",  
        dataType: "jsonp",  
        jsonp: "callback",  
        jsonpCallback:"flightHandler",  
        success: function(json){  
            alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。');  
        },  
        error: function(){  
            alert('fail');  
        }  
    });  
});  

(2)后端代码

动态生成js代码,代码里放置一个回调方法。

String code = req.getParameter("code");
String collback = req.getParameter("callback");
System.out.println(code+collback);
String str = "flightHandler({\"code\": \"CA1998\",\"price\": 1780,\"tickets\": 5});";
resp.getWriter().append(str);

四、CORS简介

1、什么是CORS

  1. CORS (跨域资源共享) 由一系列 HTTP 响应头组成,这些 HTTP 响应头决定浏览器 是否阻止前端 JS 代码跨域获取资源
  2. 浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如果接口服务器配置了 CORS 相关的 HTTP 响应头,就可以解除浏览器端的跨域访问限制

2、CORS概念

CORSCross-Origin Resource Sharing 跨源资源共享)

当一个请求url的协议域名端口三者之间任意一与当前页面地址不同即为跨域。

在日常的项目开发时会不可避免的需要进行跨域操作,而在实际进行跨域请求时,经常会遇到类似 No 'Access-Control-Allow-Origin' header is present on the requested resource.这样的报错。这样的错误,一般是由于CORS跨域验证机制设置不正确导致的。

五、CORS案例

1、普通web项目

(1)添加过滤器

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
public class CORSFilter implements Filter {
 
    public void init(FilterConfig filterConfig) throws ServletException {
    }
 
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        //*表示允许所有域名跨域
        httpResponse.addHeader("Access-Control-Allow-Origin", "*");
        httpResponse.addHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept");
        //允许跨域的Http方法
        httpResponse.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
        filterChain.doFilter(servletRequest, servletResponse);
    }
 
    public void destroy() {
    }
}

(2)web.xml配置

    <!--为了允许跨域访问-->
    <filter>
        <filter-name>CorsFilter</filter-name>
        <filter-class>org.du.personalsitemock.mockutil.CORSFilter</filter-class>
    </filter>
 
    <filter-mapping>
        <filter-name>CorsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

(3)前端代码

$.ajax({
    url: 'http://xxxx/test/cors?name=tom',
    type: 'post',
    data: '',
    //  默认情况下,标准的跨域请求是不会发送cookie的
    xhrFields: {
        withCredentials: true
    },
    success: function(rs) {
    }
})

2、Spring项目(@CrossOrigin注解)

在类或方法上添加注解即可,@CrossOrigin(origins = "*", allowCredentials = "true")

(1)后端代码

@RestController
@CrossOrigin(origins = "*", allowCredentials = "true")
public class TestController {
    
    @RequestMapping(value = "test/cors")
    public Object cors() {
        try {
            Map<String, Object> map = getParameterMap();
            System.out.println(map.toString());
            return output(map);
        } catch (Exception e) {
            e.printStackTrace();
            return output("9999", "错误", e.getMessage());
        }
    }

}

(2)前端代码

$.ajax({
    url: 'http://xxxx/test/cors?name=tom',
    type: 'post',
    data: '',
    //  默认情况下,标准的跨域请求是不会发送cookie的
    xhrFields: {
        withCredentials: true
    },
    success: function(rs) {
    }
})

3、Spring项目(添加全局过滤器)

若项目中所有接口都允许跨域访问,可增加全局过滤器允许跨域访问。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
    // 当前跨域请求最大有效时长。这里默认1天
    private static final long MAX_AGE = 24 * 60 * 60;

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址,或者http://localhost:7060
        corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
        corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法,或设置为"GET", "POST", "DELETE", "PUT"
        corsConfiguration.setMaxAge(MAX_AGE);
        source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置
        return new CorsFilter(source);
    }
}

4、Spring项目(实现WebMvcConfigurer)

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    // 当前跨域请求最大有效时长。这里默认1天
    private static final long MAX_AGE = 24 * 60 * 60;

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("*")
                .allowedHeaders("*")
                .maxAge(MAX_AGE);
    }
}

5、Nginx解决跨域

如果项目中有使用Nginx来转发请求,那也可以交由Nginx来解决跨域,但是有一点需要注意:Nginx解决跨域和后端解决跨域最好只保留一个,两种混用会出现很多奇怪的问题。
下面是nginx.conf文件解决跨域的相关配置:

server {
        listen       80;
        server_name  localhost;
        location  / {
            if ($request_method = 'OPTIONS') {
                add_header Access-Control-Allow-Origin 'http://localhost:7060';
                add_header Access-Control-Allow-Headers '*';
                add_header Access-Control-Allow-Methods '*';
                add_header Access-Control-Allow-Credentials 'true';
                return 204;
            }
            if ($request_method != 'OPTIONS') {
                add_header Access-Control-Allow-Origin 'http://localhost:7060' always;
                add_header Access-Control-Allow-Credentials 'true';
            }
            proxy_pass  http://localhost:59200; 
        }
    }

6、参考

CrossOrigin注解没有生效,解决方案集合
https://blog.csdn.net/suxiexingchen/article/details/104861803

CrossOrigin注解没有生效,解决方案集合
https://suxiexingchen.github.io/2020/03/14/36/

ajax携带cookie的两种方式
https://www.cnblogs.com/lgl1209/p/11527080.html

六、参考

9种常见的前端跨域解决方案(详解)
https://www.imooc.com/article/291931

CORS和JSONP的区别,如何解决跨域问题?
https://blog.csdn.net/SunFlower914/article/details/120691847

java web服务器实现跨域访问
https://www.iteye.com/blog/yjph83-2253863

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值