时间:2018年04月18日星期三
说明:本文部分内容均来自慕课网。@慕课网:https://www.imooc.com
教学源码:https://github.com/zccodere/s…
学习源码:https://github.com/zccodere/s…
课程介绍
什么是AJAX跨域问题
AJAX跨域场景
AJAX跨域原因
AJAX跨域问题解决思路
编写测试代码
代码编写
1.创建名为ajax-server的maven工程pom如下
2.编写AjaxServerStart类
package com.myimooc.ajax.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
*
* 标题: 启动类
* 描述: AJAX跨域讲解后端项目
*
* @author zc
* @date 2018/04/18
*/
@SpringBootApplication
public class AjaxServerStart {
public static void main(String[] args) {
SpringApplication.run(AjaxServerStart.class, args);
}
}
3.编写ResultBean类
package com.myimooc.ajax.server.vo;
import java.io.Serializable;
/**
*
* 标题: REST请求响应POJO类
* 描述: 封装请求响应结果
*
* @author zc
* @date 2018/04/18
*/
public class ResultBean implements Serializable{
private static final long serialVersiOnUID= 7867107433319736719L;
private String data;
public ResultBean(String data) {
this.data = data;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
4.编写TestController类
package com.myimooc.ajax.server.controller;
import com.myimooc.ajax.server.vo.ResultBean;
import com.myimooc.ajax.server.vo.User;
import org.springframework.web.bind.annotation.*;
/**
*
* 标题: 测试控制器
* 描述: 提供REST服务
* 使用 @CrossOrigin 注解支持跨域,可以放到类或方法上面
* @author zc
* @date 2018/04/18
*/
@RestController
@RequestMapping("/test")
//@CrossOrigin
public class TestController {
@GetMapping("/get1")
public ResultBean get1() {
System.out.println("TestController.get1");
return new ResultBean("get1ok");
}
@PostMapping("/postJson")
public ResultBean postJson(@RequestBody User user) {
System.out.println("TestController.postJson");
return new ResultBean("postJson" + user.getName());
}
@GetMapping("/getCOOKIE")
public ResultBean getCOOKIE(@COOKIEValue(value = "COOKIE1") String COOKIE1) {
System.out.println("TestController.getCOOKIE");
return new ResultBean("getCOOKIE" + COOKIE1);
}
@GetMapping("/getHeader")
public ResultBean getHeader(
@RequestHeader("x-header1") String header1,
@RequestHeader("x-header2") String header2) {
System.out.println("TestController.getHeader");
return new ResultBean("getHeader" + header1+header2);
}
}
代码编写
1.创建名为ajax-client的maven工程pom如下
2.编写index.html
3.编写application.properties
server.port=8081
4.编写AjaxClientStart类
package com.myimooc.ajax.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AjaxClientStart {
public static void main(String[] args) {
SpringApplication.run(AjaxClientStart.class, args);
}
}
5.启动AjaxServerStart和AjaxClientStart,并访问http://localhost:8081,点击发生get1请求,产生跨域问题如下
第三章:解决跨域
Chrome浏览器的跨域设置
代码编写
1.编写JsonpAdvice类
package com.myimooc.ajax.server.controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;
/**
*
* 标题: JSONP 全局处理
* 描述: 统一处理JSONP
*
* @author zc
* @date 2018/04/18
*/
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice{
public JsonpAdvice() {
// 与前端约定好回调方法名称,默认是callback
super("callback2");
}
}
2.修改index.html
// 测试方法
it("jsonp请求", function (done) {
// 服务器返回的结果
var result;
$.ajax({
url: base + "/get1",
dataType: "jsonp",
jsonp:"callback2",
success: function (res) {
result = res;
}
});
// 由于是异步请求,需要使用setTimeout来校验
setTimeout(function () {
expect(result).toEqual({
"data":"get1ok"
});
// 校验完成,通知jasmine框架
done();
},100);
});
JSONP的弊端
常见的JavaEE架构
跨域解决方向
被调用方支持跨域
使用Filter解决
编写代码
1.编写CrosFilter类
package com.myimooc.ajax.server.config;
import org.springframework.util.StringUtils;
import javax.servlet.*;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
*
* 标题: 服务端解决跨域
* 描述: 使用Filter
*
* @author zc
* @date 2018/04/18
*/
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)){
// 支持任何域名的跨域调用 且 支持带COOKIE(是被调用方域名的COOKIE,而不是调用方的COOKIE)
res.addHeader("Access-Control-Allow-Origin",origin);
}
// 指定允许的域,带COOKIE时,origin必须是全匹配,不能使用 *
// res.addHeader("Access-Control-Allow-Origin","http://localhost:8081");
// 允许所有域,但不能满足带 COOKIE 的跨域请求
// res.addHeader("Access-Control-Allow-Origin","*");
// 支持所有自定义头
String headers = req.getHeader("Access-Control-Allow-Headers");
if (!StringUtils.isEmpty(headers)){
// 允许所有header
res.addHeader("Access-Control-Allow-Headers",headers);
}
// 允许所有header
// res.addHeader("Access-Control-Allow-Headers","*");
// 指定允许的方法
// res.addHeader("Access-Control-Allow-Methods","GET");
// 允许所有方法
res.addHeader("Access-Control-Allow-Methods","*");
// 允许浏览器在一个小时内,缓存跨域访问信息(即上面三个信息)
res.addHeader("Access-Control-Max-Age","3600");
// 启用 COOKIE
res.addHeader("Access-Control-Allow-Credentials","true");
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
2.编写FilterConfig类
package com.myimooc.ajax.server.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
* 标题: 配置类
* 描述: 注册CrosFilter
*
* @author zc
* @date 2018/04/18
*/
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean registrationBean(){
FilterRegistrationBean filter = new FilterRegistrationBean();
filter.addUrlPatterns("/*");
filter.setFilter(new CrosFilter());
return filter;
}
}
3.启动AjaxServerStart和AjaxClientStart,并访问http://localhost:8081,跨域解决
简单请求与非简单请求
Nginx配置
编写b.com.conf
server{
listen 80;
server_name b.com;
location /{
proxy_pass http://localhost:8080/;
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Headers $http_access_control_allow_headers;
if ($request_method = OPTIONS){
return 200;
}
}
}
Apache配置
ServerName b.com
ErrorLog "logs/b.com-error.log"
CustomLog "logs/b.com-access.log" common
ProxyPass / http://localhost:8080/
# 把请求头的origin值返回到Access-Control-Allow-Origin字段
Header always set Access-Control-Allow-Origin "expr=%{req:origin}"
# 把请求头的Access-Control-Allow-Headers值返回到Access-Control-Allow-Headers字段
Header always Access-Control-Allow-Headers "expr=%{Access-Control-Allow-Headers}"
Header always set Access-Control-Allow-Methods "*";
Header always set Access-Control-Max-Age "3600";
Header always set Access-Control-Allow-Credentials ""true";
# 处理预检命令OPTIONS,直接返回204
RewriteEngine On
RewriteCond %{REQUEST_METHOD}OPTIONS
RewriteRule ^(.*)$"/" [R=204,L]
Spring框架支持
使用Nginx反向代理实现
编写a.com.conf
server{
listen 80;
server_name a.com;
location /{
proxy_pass http://localhost:8081/;
}
location /ajaxserver{
proxy_pass http://localhost:8080/test/;
}
}
使用Apache反向代理实现
第四章:课程总结
ServerName a.com
ErrorLog "logs/a.com-error.log"
CustomLog "logs/a.com-access.log" common
ProxyPass / http://localhost:8081/
ProxyPass /ajaxserverapache http://localhost:8080/test
课程总结