CORS 定义
Cross-Origin Resource Sharing(CORS)跨来源资源共享是一份浏览器技术的规范,提供了 Web 服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略,是 JSONP 模式的现代版。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以让网页设计师用一般的 XMLHttpRequest,这种方式的错误处理比 JSONP 要来的好。另一方面,JSONP 可以在不支持 CORS 的老旧浏览器上运作。现代的浏览器都支持 CORS。
CORS 对比 JSONP
都能解决 Ajax直接请求普通文件存在跨域无权限访问的问题
- JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求
- 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理
- JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS
方法一:Controller增加spring注解:
@CrossOrigin
这里虽然指SpringBoot但是SpringMVC也是一样的,要求在Spring4.2及以上的版本
方法二:使用filter拦截器:
Application增加FilterRegistrationBean的@Bean:
package com.xc.boot; import com.xc.boot.filter.CrosFilter; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; @SpringBootApplication public class BootApplication { public static void main(String[] args) { SpringApplication.run(BootApplication.class, args); } @Bean public FilterRegistrationBean registerFilter(){ FilterRegistrationBean bean = new FilterRegistrationBean(); bean.addUrlPatterns("/*"); bean.setFilter(new CrosFilter()); return bean; } }
创建CrosFilter拦截器类:
package com.xc.boot.filter; import org.springframework.util.StringUtils; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CrosFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse res = (HttpServletResponse) response; HttpServletRequest req = (HttpServletRequest) request; String origin = req.getHeader("Origin"); if (!StringUtils.isEmpty(origin)) { System.out.println("origin:" + origin); res.addHeader("Access-Control-Allow-Origin", origin);//允许其他域名访问 } String headers = req.getHeader("Access-Control-Request-Headers"); if (!StringUtils.isEmpty(headers)) { res.addHeader("Access-Control-Allow-Headers", headers);//允许的请求头字段 } res.addHeader("Access-Control-Allow-Methods", "*");//允许的请求类型 res.addHeader("Access-Control-Max-Age", "1800");//预检结果缓存时间 res.addHeader("Access-Control-Allow-Credentials", "true");//是否允许后续请求携带认证信息(cookies),该值只能是true,否则不返回 chain.doFilter(request, response); } @Override public void destroy() { } }
创建测试controler类:
package com.xc.boot.controller; import com.xc.boot.common.ResultBean; import com.xc.boot.entity.User; import org.springframework.web.bind.annotation.*; import java.util.Date; @RestController @RequestMapping("ajax") public class AjaxController { @RequestMapping("get1") public ResultBean index() { System.out.println("get1:" + new Date()); return new ResultBean("get1 ok"); } @PostMapping("/postJson") public ResultBean postJson(@RequestBody User user) { System.out.println("postJson:" + new Date()); return new ResultBean("postJson " + user.getName()); } @GetMapping("/getCookie") public ResultBean getCookie(@CookieValue(value = "cookie1") String cookie1) { System.out.println("getCookie:" + new Date()); return new ResultBean("getCookie " + cookie1); } @GetMapping("/getHeader") public ResultBean getHeader(@RequestHeader(value = "x-header1") String header1, @RequestHeader(value = "x-header2") String header2) { System.out.println("getHeader:" + new Date()); return new ResultBean("getHeader " + header1 + " " + header2); } }
创建测试ajax:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>AJAX跨越完全讲解</title> <script src="jquery-1.11.3.js"></script> <link rel="stylesheet" type="text/css" href="jasmine-2.8.0/jasmine.css"> <script src="jasmine-2.8.0/jasmine.js"></script> <script src="jasmine-2.8.0/jasmine-html.js"></script> <script src="jasmine-2.8.0/boot.js"></script> </head> <body> <script> function get1() { $.getJSON("http://localhost:8082/boot/ajax/get1").then(function(result) { console.log(result); }); } // 每一个测试用例的超时时间 jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; // 请求的接口的前缀 var base = "http://localhost:8082/boot/ajax"; //测试模块 describe("晓风轻-ajax跨越完全讲解", function() { // 测试方法 it("get1请求", function(done) { // 服务器返回的结果 var result; $.getJSON(base + "/get1").then(function(jsonObj) { result = jsonObj; }); // 由于是异步请求,需要使用setTimeout来校验 setTimeout(function() { expect(result).toEqual({ "data" : "get1 ok" }); // 校验完成,通知jasmine框架 done(); }, 100); }); // 测试方法 /*it("jsonp请求", function(done) { // 服务器返回的结果 var result; $.ajax({ url: base +"/get1", dataType: "jsonp", jsonp: "callback2", cache:true, success: function(json){ result = json; } }); // 由于是异步请求,需要使用setTimeout来校验 setTimeout(function() { expect(result).toEqual({ "data" : "get1 ok" }); // 校验完成,通知jasmine框架 done(); }, 100); });*/ it("postJson请求", function(done) { // 服务器返回的结果 var result; $.ajax({ type : "post", url: base + "/postJson", contentType : "application/json;charset=utf-8", data: JSON.stringify({name: "xc"}), success: function(json){ result = json; } }); // 由于是异步请求,需要使用setTimeout来校验 setTimeout(function() { expect(result).toEqual({ "data" : "postJson xc" }); // 校验完成,通知jasmine框架 done(); }, 100); }); it("getCookie请求", function(done) { // 服务器返回的结果 var result; $.ajax({ type : "get", url: base + "/getCookie", xhrFields:{ withCredentials:true }, success: function(json){ result = json; } }); // 由于是异步请求,需要使用setTimeout来校验 setTimeout(function() { expect(result).toEqual({ "data" : "getCookie xc" }); // 校验完成,通知jasmine框架 done(); }, 100); }); it("getHeader请求", function(done) { // 服务器返回的结果 var result; $.ajax({ type : "get", url: base + "/getHeader", headers:{ "x-header1" : "AAA" }, beforeSend: function(xhr){ xhr.setRequestHeader("x-header2","BBB") }, success: function(json){ result = json; } }); // 由于是异步请求,需要使用setTimeout来校验 setTimeout(function() { expect(result).toEqual({ "data" : "getHeader AAA BBB" }); // 校验完成,通知jasmine框架 done(); }, 100); }); }); </script> </body> </html>