spring boot 跨域访问处理
- 问题场景:由于项目中使用到跨域访问,今天也得到高人指点,所以写出来分享给大家。可能是考虑到前后端分离,前端后端服务器不在一台机器上,出现这种跨域访问的情况。正常情况下本地访问是没有问题,但是遇到这种非同一台服务器的情况下,就会报错 Access-Control-Allow-Origin 。具体报错内容不记得了。
- 问题解决方案一:采用添加拦截器的方式对请求添加跨域访问的头,允许跨域访问。
package com.meicloud.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; public class CommonInterceptor extends HandlerInterceptorAdapter { private final static Logger logger = Logger.getLogger(CommonInterceptor.class); @Override public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception { logger.info("添加跨域访问头配置,Access-Control-Allow-Origin:*"); //跨域访问CORS response.addHeader("Access-Control-Allow-Origin", "*"); response.addHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE,HEAD"); response.addHeader("Access-Control-Allow-Headers", "S_ID,content-type"); response.addHeader("Access-Control-Max-Age", "3600000"); response.addHeader("Access-Control-Allow-Credentials", "true"); //让请求,不被缓存, response.setHeader("Cache-Control", "no-cache"); response.setHeader("Cache-Control", "no-store"); response.setHeader("Pragma", "no-cache"); response.setDateHeader("Expires", 0); logger.debug("==================================preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { logger.debug("==================================postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { logger.debug("==================================afterCompletion"); } }
上面是拦截器内容,下面是对拦截器的配置。
package com.meicloud.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import com.meicloud.interceptor.CommonInterceptor; @ComponentScan @Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { // TODO Auto-generated method stub registry.addInterceptor(new CommonInterceptor()).addPathPatterns("/getDOC"); } }
然后就可以在controller中使用他了,下面是我的controller
@ResponseBody
@RequestMapping(value="/getDOC",method=RequestMethod.POST)
public BaseReturn getDOC(@RequestBody MailEntity mailEntity, HttpServletRequest request, HttpServletResponse response, HttpSession httpSession){
log.info("excute controllor HomeController.getDOC");
BaseReturn baseReturn = new BaseReturn();
String name = mailEntity.getName();
String company = mailEntity.getCompany();
String departments = mailEntity.getDepartments();
String job = mailEntity.getJob();
String email = mailEntity.getEmail();
String phone = mailEntity.getPhone();
String doc = mailEntity.getDoc();
try {
if(name==null||name.equals("")){
throw new CommenException("姓名不能为空!");
}
if(email==null||email.equals("")){
throw new CommenException("Email不能为空!");
}
if(phone==null||phone.equals("")){
throw new CommenException("电话号码不能为空!");
}
if(doc==null||doc.equals("")){
throw new CommenException("文档不能为空!");
}
} catch (Exception e1) {
baseReturn.setCode(ReturnType.FAIL);
baseReturn.setMsg(e1.getMessage());
log.error(e1.getMessage());
return baseReturn;
}
try {
// iMailClent.sendMail(mailEntity);
iMailClent.sendHtmlMail(mailEntity);
baseReturn.setCode(ReturnType.SUCCESS);
} catch (Exception e) {
e.printStackTrace();
baseReturn.setCode(ReturnType.FAIL);
baseReturn.setMsg("发送邮件失败!");
log.error(e.getMessage());
}
return baseReturn;
}
接下来是前端的调用,前端采用ajax post 请求
var params = { name:name, company:company, departments:departments, job:job, email:email, phone:phone, doc:'/doc/api.doc' }; var type = 'POST'; var url = Config.host + url; $.ajax({ url : url, data : JSON.stringify(params), type : type, contentType : "application/json", async : false, success : function(data) { //TODO 成功 }, error : function(data) { //TODO 失败 } });
- 问题解决方案二:使用 JSONP 来实现跨域访问。直接上代码,前端代码为:
url = 'http://localhost:9999/getDOC' + '?name=' + params.name + '&company=' + params.company + '&departments=' + params.departments + '&job=' + params.job + '&email=' + params.email + '&phone=' + params.phone + '&doc=' + params.doc; $.ajax({ url : url, type : 'get', async : false, dataType : "jsonp", jsonpCallback : "callback", success : function(data) { //TODO 成功 }, error : function(data) { //TODO 失败 } });
限制调用方式为 get ,数据类型为 jsonp。后端也必须响应 JSONPObject 对象。
@ResponseBody @RequestMapping(value="/getDOC",method=RequestMethod.GET) public JSONPObject getDOC(HttpServletRequest request,String callback){ BaseReturn baseReturn = new BaseReturn(); String name = request.getParameter("name"); String company = request.getParameter("company"); String departments = request.getParameter("departments"); String job = request.getParameter("job"); String email = request.getParameter("email"); String phone = request.getParameter("phone"); String doc = request.getParameter("doc"); try { if(name==null||name.equals("")){ throw new CommenException("姓名不能为空!"); } if(email==null||email.equals("")){ throw new CommenException("Email不能为空!"); } if(phone==null||phone.equals("")){ throw new CommenException("电话号码不能为空!"); } if(doc==null||doc.equals("")){ throw new CommenException("文档不能为空!"); } } catch (Exception e1) { baseReturn.setCode(ReturnType.FAIL); baseReturn.setMsg(e1.getMessage()); log.error(e1.getMessage()); return new JSONPObject(callback, baseReturn); } MailEntity mailEntity = new MailEntity(); mailEntity.setCompany(company); mailEntity.setDepartments(departments); mailEntity.setDoc(doc); mailEntity.setEmail(email); mailEntity.setJob(job); mailEntity.setName(name); mailEntity.setPhone(phone); try { iMailClent.sendHtmlMail(mailEntity); baseReturn.setCode(ReturnType.SUCCESS); } catch (Exception e) { e.printStackTrace(); baseReturn.setCode(ReturnType.FAIL); baseReturn.setMsg("发送邮件失败!"); log.error(e.getMessage()); } return new JSONPObject(callback, baseReturn); }
- 今天得到高人指点,原来有一种更加简便的方法,可以实现。不过原理肯定都是一样的,通过给请求添加消息头来设置跨域访问,这点是无疑的。新的解决办法就是给controller或方法添加 @CrossOrigin 注解,具体详情请参考:http://spring.io/blog/2015/06/08/cors-support-in-spring-framework
@ResponseBody @RequestMapping(value="/getDOC",method=RequestMethod.POST) @CrossOrigin //使用注解方式添加跨域访问消息头 public BaseReturn getDOC(@RequestBody MailEntity mailEntity, HttpServletRequest request, HttpServletResponse response, HttpSession httpSession){ log.info("excute controllor HomeController.getDOC");
就这么多了吧,在网上看到还有添加过滤器的,当然都是差不多的做法。