1.跨域
1.1同源策略
规定:如果浏览器的地址与Ajax的请求地址–>协议名称://域名地址:端口号
如果都相同则满足同源策略,浏览器可以正常解析返回
如果三者有任意一个不满足,则违反同源策略,浏览器不会解析返回值
1.2跨域
由于业务需要,通常A服务器中的数据可能来源于B服务器. 当浏览器通过网址解析页面时,如果页面内部发起ajax请求.如果浏览器的访问地址与Ajax访问地址不满足同源策略时,则称之为跨域请求.
跨域要素:
1.浏览器内部发生
2.解析ajax
3.违反同源策略
JSONP: 用户利用jsonp向服务器端动态获取数据的过程. 主体是用户.
CORS: 服务器是否允许客户端访问的技术. 主体是服务器.
2.JSONP
jsonp只能支持get请求
1.利用javaScript中的src属性可以跨域的访问
web页面调用manage页面
<script type="text/javascript" src="http://manage.jt.com/test.json"></script>
2.提前准备一个回调函数 callback()
/*定义回调函数 */
function hello(data){
alert(data.name);
}
3.将返回值结果进行特殊的格式封装. callback(JSON数据)
hello({"id":"1","name":"tom"})
web服务器发起请求
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试JSON跨域问题</title>
<script type="text/javascript">
/*JS是解释执行的语言 */
/*定义回调函数 */
function hello(data){
alert(data.name);
}
</script>
<!--该json一直保存到浏览器中等待调用,但是没有函数名称无法调用 -->
<!--<script type="text/javascript" src="hello({"id":"1","name":"tom"})"></script>-->
<script type="text/javascript" src="http://manage.jt.com/test.json"></script>
<script type="text/javascript" src="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
</head>
<body>
<h1>JS跨域问题</h1>
</script>
</body>
</html>
manage服务器接受请求
hello({"id":"1","name":"tom"})
2.1JSONP高级API
编辑前端web页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSONP测试</title>
<script type="text/javascript" src="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){ //让页面加载完成之后再次执行
alert("测试访问开始!!!!!")
$.ajax({
url:"http://manage.jt.com/web/testJSONP",
type:"get", //jsonp只能支持get请求
dataType:"jsonp", //dataType表示返回值类型
jsonp: "callback", //指定参数名称
jsonpCallback: "hello", //指定回调函数名称
success:function (data){ //data经过jQuery封装返回就是json串
alert(data.itemId);
alert(data.itemDesc);
//转化为字符串使用
//var obj = eval("("+data+")");
//alert(obj.name);
}
});
})
</script>
</head>
<body>
<h1>JSON跨域请求测试</h1>
</body>
</html>
毫秒数作用: 由于浏览器进行业务请求时可能有缓存操作,所以添加毫秒数,避免浏览器将结果缓存.导致业务异常.
编辑后端manage服务器
package com.jt.web;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.pojo.ItemDesc;
import com.jt.util.ObjectMapperUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class WebJSONPController {
/**
* 完成JSONP跨域访问
* url地址: http://manage.jt.com/web/testJSONP?callback=hello&_=1605584709377
* 参数: callback 回调函数的名称
* 返回值: callback(json)
*/
@RequestMapping("/web/testJSONP")
public JSONPObject testJSONP(String callback){
ItemDesc itemDesc = new ItemDesc();
itemDesc.setItemId(1000L).setItemDesc("JSONP远程调用!!!");
JSONPObject jsonpObject = new JSONPObject(callback, itemDesc);
return jsonpObject;
}
}
优缺点:
JSONP 的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行。
JSONP 的缺点是:它只支持 GET 请求,而不支持 POST 请求等其他类型的 HTTP 请求
3.CORS
3.1CORS介绍
因为出于安全的考虑, 浏览器不允许Ajax调用当前源之外的资源. 即浏览器的同源策略.
CORS需要浏览器和服务器同时支持。目前,所有主流浏览器都支持该功能,IE浏览器不能低于IE10。在浏览器端, 整个CORS通信过程都是浏览器自动完成,在请求之中添加响应头信息,如果服务器允许执行跨域访问.,则浏览器的同源策略放行.
3.2CORS的配置信息
package com.jt.config;
/**
* @author Osiris
* @date 2020/12/10 14:02
*/
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* cors的跨域配置
* 思路:再请求的响应头中添加访问信息
* WebMvcConfigurer:WEB项目的全局配置
* addMapping():哪些请求可以进行跨域操作
* addMapping("/**"):所有访问后端服务器的请求都允许跨域
* /*:拦截一级目录 /**:拦截所有目录
* allowedOrigins():允许那些网站跨域
* allowCredentials():请求跨域时是否允许携带cookie/session相关
*
*
*/
@Configuration
public class CORSConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) { //registry:注册器
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true);
//.maxAge() //默认30分钟
//.allowedMethods() //允许请求类型 (get,head)
}
}
3.3完成用户数据校验
编辑JT-SSO-UserController
package com.jt.controller;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.pojo.User;
import com.jt.service.UserService;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 业务需求: 查询所有用户信息
* url: sso.jt.com localhost:8093 /findAll
* 返回值: List<User>
*/
@RequestMapping("/findAll")
public List<User> findAll(){
return userService.findAll();
}
/**
* 需求:实现用户信息校验
* 校验步骤: 需要接收用户的请求,之后利用RestFul获取数据,
* 实现数据库校验,按照JSONP的方式返回数据.
* url地址: http://sso.jt.com/user/check/admin123/1?r=0.8&callback=jsonp16
* 参数: restFul方式获取
* 返回值: JSONPObject
*/
@RequestMapping("/check/{param}/{type}")
public JSONPObject checkUser(@PathVariable String param,
@PathVariable Integer type,
String callback){
//只需要校验数据库中是否有结果
boolean flag = userService.checkUser(param,type);
SysResult sysResult = SysResult.success(flag);
return new JSONPObject(callback, sysResult);
}
}
编辑JT-SSO UserService
package com.jt.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class UserServiceImpl implements UserService{
@Autowired
private UserMapper userMapper;
private static Map<Integer,String> paramMap = new HashMap<>();
static {
paramMap.put(1, "username");
paramMap.put(2, "phone");
paramMap.put(3, "email");
}
@Override
public List<User> findAll() {
return userMapper.selectList(null);
}
/**
* 校验数据库中是否有数据....
* Sql: select count(*) from tb_user where username="admin123";
* 要求:返回数据true用户已存在,false用户不存在
*/
@Override
public boolean checkUser(String param, Integer type) {
String column = paramMap.get(type);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(column,param);
int count = userMapper.selectCount(queryWrapper);
return count>0?true:false;
//return count>0;
}
}
全局异常处理
package com.jt.aop;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.vo.SysResult;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
@RestControllerAdvice //定义全局异常处理
public class SystemException {
//遇到运行时异常时方法执行.
//JSONP报错 返回值 callback(JSON) 如果请求参数中包含callback参数,则标识为跨域请求
@ExceptionHandler({RuntimeException.class})
public Object fail(Exception e, HttpServletRequest request){
e.printStackTrace(); //输出异常信息.
String callback = request.getParameter("callback");
if(StringUtils.isEmpty(callback)){
//如果参数为空表示 不是跨域请求.
return SysResult.fail();
}else{
//有callback参数,表示是跨域请求.
SysResult sysResult = SysResult.fail();
return new JSONPObject(callback,sysResult);
}
}
}
关于跨域
1.什么叫跨域 浏览器解析Ajax时,发起url请求违反了同源策略时,称之为跨域.
2.什么时候用跨域 一般A服务器需要从B服务器中获取数据时,可以采用跨域的方式.
3.什么是JSONP JSONP是JSON的一种使用模式 利用javaScript中的src属性进行跨域请求.(2.自定义回调函数,3.将返回值进行特殊格式封装)
4.什么是CORS CORS是当前实现跨域的主流方式,现在所有的主流浏览器都支持,需要在服务器端配置是否允许跨域的配置. 只要配置了(在响应头中添加允许跨域的标识),则同源策略不生效,则可以实现跨域.