- 問題場景:由於項目中使用到跨域訪問,今天也得到高人指點,所以寫出來分享給大家。可能是考慮到前后端分離,前端后端服務器不在一台機器上,出現這種跨域訪問的情況。正常情況下本地訪問是沒有問題,但是遇到這種非同一台服務器的情況下,就會報錯 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");
就這么多了吧,在網上看到還有添加過濾器的,當然都是差不多的做法。