spring boot 跨域訪問處理


  1. 問題場景:由於項目中使用到跨域訪問,今天也得到高人指點,所以寫出來分享給大家。可能是考慮到前后端分離,前端后端服務器不在一台機器上,出現這種跨域訪問的情況。正常情況下本地訪問是沒有問題,但是遇到這種非同一台服務器的情況下,就會報錯 Access-Control-Allow-Origin 。具體報錯內容不記得了。
  2. 問題解決方案一:采用添加攔截器的方式對請求添加跨域訪問的頭,允許跨域訪問。
    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 失敗
            }
        });

     

  3. 問題解決方案二:使用 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);
        }
        

     

  4. 今天得到高人指點,原來有一種更加簡便的方法,可以實現。不過原理肯定都是一樣的,通過給請求添加消息頭來設置跨域訪問,這點是無疑的。新的解決辦法就是給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");

    就這么多了吧,在網上看到還有添加過濾器的,當然都是差不多的做法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM