Lesson16 实现跨域请求的两种方式:JSONP 和 CORS

1 什么是跨域

就是A服务器去请问访问B服务器中的资源。
在这里插入图片描述

1.1 跨域访问的测试

1.1.1 测试1:同一个服务器中(jt-manage)中的测试

浏览器要是想通过jt-manage服务器去访问jt-manage项目中的test.html,通过客户端发送ajax请求(请求test.json)。
jt-manage服务器可以给客户端返回test.json中“name”对应的value:tom
这个结果不会被浏览器拦截掉。客户端可以正常显示结果。
test.html和test.json 这两个文件都在jt-manage中的webapp目录下。

说明:

  1. 浏览器中输入的网址url: http://manage.jt.com/test.html
  2. ajax请求中的地址url: http://manage.jt.com/test.json

通过对比这两个url发现: 请求协议名称:// 域名 :端口号 这3项都相同时,客户端能正常收到服务器响应回来的数据,并展现出来。

1.1.2 测试2:在不同的服务器中(jt-web和jt-manage)之间的测试

浏览器要是想通过jt-web服务器中的test.html,去访问jt-manage中的test.json文件,通过客户端发送ajax请求(请求test.json)。
jt-manage服务器给客户端返回test.json中“name”对应的value:tom
这个结果被浏览器拦截掉(因为浏览器发现,ajax请求是jt-web的前端发出去的,得到的结果却是jt-manage返回的,这是不可以的)。jt-web的客户端不会显示结果。

说明:

  1. 浏览器中输入的网址url: http://www.jt.com/test.html
  2. ajax请求中的地址url: http://manage.jt.com/test.json

通过对比这两个url发现: 这两个url的域名不相同,客户端没有正常显示结果数据。

1.2 同源策略介绍

同源策略规定:
浏览器在解析客户端发送的ajax请求时,如果发现ajax请求的协议名称://请求的域名:请求的端口号与 浏览器网址中输入的地址都相同时,浏览器可以正确的解析返回值.从而客户端能成功展现服务器的响应数据。
客户端发送的这个访问叫同域访问

跨域访问
但是如果违反了同源策略中的任意一条,则叫做跨域访问.
浏览器出于安全性的考虑.不予解析返回值(请求会被服务器正常处理,但是客户端接收不到返回值).

易错点:
http://localhost:8091/text.html 与
http://manage.jt.com/text.html
属于跨域访问(域名和端口号都不同):
nginx是将localhost 映射到 manage.jt.com上的,它俩不能看做是同一个域名。
并且manage.jt.com的端口号后面是80(nginx默认的端口号)。

1.3 实现跨域的方式一:通过JSONP

JSONP,全称:JSON with Padding 。它是json的一种使用模式,(意思就是它有自己独特的处理json串的方法。)

1.3.1 JSONP实现跨域的原理(步骤)

通常情况下,A服务器是无法得到B服务器的返回值的。
但A服务器如果用了JSONP方式,就能访问B服务器。它是怎么做到的呢?

主要原因:
A服务器中的.html文件中,script标签中,多配置了src这么一个属性
在这里插入图片描述src属性不受同源策略的约束.可以获取B服务器数据.
也就是说,
第一步,要在A服务器的html文件(浏览器url后面接的是哪个html,就在A服务器中找哪个html)中的script标签中,添加src属性,src后面跟的就是想要访问的B服务器的文件的地址。

第二步,自定义回调函数的名称,可以任意起名
在A服务器的html文件中,
在这里插入图片描述
第三步,将B服务器中的返回的json串,进行特殊的封装。
即把json串用我上一步自定义的回调函数的名称包裹。
在B服务器中找到要返回的json串结果。
在这里插入图片描述

1.3.2 JSONP跨域方式的优化

1.3.1中的3大步骤是jsonp实现跨域的根本。
但这个方法比较麻烦,待优化的2个点:

1:A服务器中
在这里插入图片描述这种将请求写在src中,非常不方便操作,能否封装为ajax调用方式?

2:B服务器中这种将回调函数的名字写死,也是不好的。怎么才能动态获取呢?
在这里插入图片描述
其实:在浏览器中输入的地址一般都是这样的:
在这里插入图片描述

后面的jQuery111…都是回调函数的名字,前面的callback是接收回调函数名字的一个变量。
所以,将在B服务器中需要写回调函数名字的地方,就把callback这个变量传过去就行了。

1.3.3 JSONP:通过ajax的形式发送请求

<script type="text/javascript">
	$(function(){
		alert("测试访问开始!!!!!")
		$.ajax({
			url:"http://manage.jt.com/web/testJSONP",
			type:"get",				//jsonp只能支持get请求 src只能是get请求
			dataType:"jsonp",       //dataType表示返回值类型   (平时都是json,可以省略不写)
			jsonp: "callback",    //指定接收回调函数的变量的名称   通常都写callback    
			jsonpCallback: "hello",  //指定回调函数名称    这样浏览器中的回调函数名后面就不会跟一长串数字了
			success:function (data){   //data经过jQuery封装返回就是json串
				alert(data.itemId);
				alert(data.itemDesc);
			}
		});	
	})
</script>

1.3.4 编辑jt-manage中UserController,用以返回数据

既然jt-web人家发起请求要访问jt-manage中的资源,那jt-manage中就要有一个Controller来接这个请求。
在jt-manage中新建一个UserController

@RestController
public class JSONPController {
@RequestMapping("/web/testJSONP")
    public String jsonp(String callback){ //callback是个变量  由客户端发ajax请求时,传来,比如可以是hello 可以是abc....
        ItemDesc itemDesc = new ItemDesc();
        itemDesc.setItemId(888L).setItemDesc("封装后的跨域测试~~~~");
        //我自己手动将itemDesc对象转换为json字符串
        String json = ObjectMapperUtil.toJSON(itemDesc);
        return callback+"("+json+")";   //JSONP中规定返回的json串要放在回调函数中
    }
}

1.3.5 通过JSONObject对象(SpringBoot提供的),简化我手动转化json字符串的操作

@RestController
public class JSONPController {

    /**
     * 测试用jquery封装后的跨域请求,能否成功
     * url地址:  http://manage.jt.com/web/testJSONP?callback=jQuery1111008886989701217463_1600139002367&_=1600139002368
     * 返回值的类型应该是经过特殊格式封装的json数据 :   callback(json字符串)
     * 也是一种字符串,所以jsonp方法的返回值那才能写String
     * SpringBoot中为了方便我的跨域的操作,就给我提供了一个API对象JSONPObject,它可以自动帮我把回调函数名和返回的结果拼接起来。就不用我自己手动拼接了。
     */
    @RequestMapping("/web/testJSONP")
    public JSONPObject jsonp(String callback){ //callback是个变量 比如可以是hello 可以是abc....
        ItemDesc itemDesc = new ItemDesc();
        itemDesc.setItemId(888L).setItemDesc("用SpringBoot中提供的API封装后的跨域测试~~~~");
        //通过JSONPObject拼接回调函数名和服务器返回的结果
        JSONPObject jsonpObject = new JSONPObject(callback, itemDesc);
        return jsonpObject;
    }
}

1.3.6 关于ajax请求时间毫秒数的说明

说明:
由于浏览器内部有缓存机制,所以如果遇到了一个相同的请求地址(即回调函数名相同了),浏览器可能会展现的是之前的结果(即使用缓存),但是有些数据必须要求浏览器重数据库中动态获取数据,为了避免这种情况,一般在url最后添加随机数或者时间毫秒数区分url请求(区分回调函数名)
在这里插入图片描述

1.4 实现跨域的方式二:通过CORS

CORS实现跨域的原理与JSONP完全不同。
它是让B服务器给返回的数据(Response对象)上进行一些标识,浏览器看到这些标识,就不再拦截了,A服务器的客户端就接收到了这些数据。
就好比,我(A服务器)去超市(B服务器)买东西,当我出超市时,如果没有CORS方法,保安(浏览器)会拦截住我买的东西。
而如果保安看到了我的购物小票(一些标识),就会把这些东西给我,让我带走。

由于JSONP跨域仅支持客户端发get请求(跨域请求通常也只发get请求就够用了),但如果要发get/post/put/delete这几种ajax请求,就要用CORS。
由于当下的跨域的业务比较常见,所有的主流的浏览器默认支持跨域.
CORS的核心是 需要在被访问的服务器端配置 是否允许被跨域访问。

1.4.1 前情回顾

在没用JSONP和CORS时,A服务器尝试跨域访问B服务器时,浏览器中的报错信息是:
在这里插入图片描述
翻译一下就是:
在这里插入图片描述

1.4.2 CORS实现跨域访问的原理

通过在B浏览器中添加配置类,进而返回的Response对象上就被标识了各种标签。
浏览器看到后,就不拦截了。

1.4.3 编辑CORS配置类

在jt-common中添加CORS的配置类

@Configuration
public class CORSConfig implements WebMvcConfigurer {

    //记得这个CORSConfig类要实现WebMvcConfigurer接口
    //而这个WebMvcConfigurer接口就相当于tomcat服务器安装目录下的那个web.xml配置文件

    /**
     * 通过CORS实现跨域请求
     * 需要配置服务器端程序,通过配置了这些内容,被请求的服务器就允许这样的跨域请求访问它,所以浏览器知道了那个被请求的服务器允许这些了。数据回到浏览器时,浏览器就不拦截了。
     * 方法说明:
     *      1.addMapping("/**")  允许访问哪些资源时可以跨域(比如/item,/itemDesc,/item/42358.html,/itemDesc/test.html)
     *                           "/**"  就是可以访问任意目录下的任意资源时,可以跨域请求访问
     *      2.allowedOrigins("*")  允许哪个服务器可以去发起跨域访问请求,括号里填想发起跨域访问的服务器的url 比如:http://www.jt.com:80/)
     *                           "*"    就是任意url的服务器都可以去发起跨域请求,并得到结果
     *      3.allowCredentials(true)  服务器在发送跨域请求时,是否可以携带cookie等参数   true表示可以携带
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
       registry.addMapping("/**")
               .allowedOrigins("*")
               .allowCredentials(true);
    }
}

1.4.4 CORS实现跨域访问的效果测试

前提:
jt-manage服务器返回的json字符串改为普通的形式:
在这里插入图片描述
jt-web假装访问的是自己家的test.html文件,在浏览器中的url为www.jt.com/test.html
实际上,通过test.html文件会去访问jt-manage中的test.json
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值