莫大人

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");

    就这么多了吧,在网上看到还有添加过滤器的,当然都是差不多的做法。

posted on 2016-11-02 18:03  莫大人  阅读(1700)  评论(0编辑  收藏  举报

导航