zoukankan      html  css  js  c++  java
  • ajax跨域解决

    因WEB安全原因,Ajax默认情况下是不能进行跨域请求的,遇到这种问题,自然难不倒可以改变世界的程序猿们,于是JSONP(JSON with Padding)被发明了,其就是对JSON的一种特殊,简单来说就是在原有的JSON数据上做了点手脚,从而达到可以让网页可以跨域请求。在现在互联网技术对“前后分离”大规模应用的时期,JSONP可谓意义重大啊。

    假设我们原来的JSON数据为 {“hello”:”你好”,”veryGood”:”很好”} 
    那么对应的JSONP的格式就是 functionName({“hello”:”你好”,”veryGood”:”很好”}) ,其中“functionName”不是固定值,自己定义。

    在SpringMVC中实现支持JSONP总结为如下几点: 
    1. response 响应类型为 application/javascript 
    2. 进行json请求的URL中需要携带参数 jsonp 或 callback,并指定值。 
    如 http://mydomain/index.jsonp?callback=myfun 
    或 http://mydomain/index.jsonp?jsonp=myfun 
    其中 myfun 就为最终包裹在原有JSON外的函数名 
    3. 如果你在配置文件中配置过 MappingJacksonJsonView 那么请修改使用 MappingJackson2JsonView 
    4. Controller 中的方法需要返回 ModelAndView 或者未使用 @ResponseBody 注解的返回 String 页面。也就是说最终怎么呈现结果,交由SpringMVC来给我们完成。 
    5. 针对显式注解 @ResponseBody 的方法 (我们本来就是直接响应JSON的),我们需要做特殊处理,使用 MappingJacksonValue 进行封装处理。

    说的有点抽象,下面看实际怎么做。 
    当然我们的原则就是“不对原有已经实现的代码进行任何修改”。

    本文代码以SpringBoot为例。

    使用 WebMvcConfigurerAdapter 配置 ContentNegotiatingViewResolver ,代码如下:

    @Configuration
    public class MyWebAppConfigurer 
            extends WebMvcConfigurerAdapter {
    
        private static final Logger logger = LoggerFactory.getLogger(MyWebAppConfigurer.class);
    
        @Override
        public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
            configurer.defaultContentType(MediaType.TEXT_HTML)
            .ignoreAcceptHeader(true);
        }
    
        /*
         * Configure ContentNegotiatingViewResolver
         */
        @Bean
        public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
            ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
            resolver.setContentNegotiationManager(manager);
    
            // Define all possible view resolvers
            List<ViewResolver> resolvers = new ArrayList<ViewResolver>();
    
            resolvers.add(new JsonViewResolver());
    
            resolver.setViewResolvers(resolvers);
            return resolver;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    JsonViewResolver.java

    public class JsonViewResolver implements ViewResolver{
    
        private MappingJackson2JsonView view;
    
        public JsonViewResolver() {
            super();
            view = new MMappingJackson2JsonView();
            view.setPrettyPrint(true);
        }
    
        public View resolveViewName(String viewName, Locale locale) throws Exception {
            return view;
        }
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    MMappingJackson2JsonView.java 
    这个类并不是必须的,我写出来也是为了说明如果遇到和我一样的问题时怎么解决,注意看代码中的注释说明

    public class MMappingJackson2JsonView extends MappingJackson2JsonView {
    
        /**
         * 排除JSON转换的时候 model 中自动加入的对象<br/>
         * 如果你在项目中使用了 @ControllerAdvice , 要特别注意了,我们在这里就是要排除掉因为@ControllerAdvice自动加入的值
         *
         */
        @Override
        protected Object filterModel(Map<String, Object> model) {
            Map<String, Object> result = new HashMap<String, Object>(model.size());
            if (model != null) {
                for (Map.Entry<String, Object> entry : model.entrySet()) {
                    if (!"urls".equals(entry.getKey())) {// 对我在项目中使用 @ControllerAdvice 统一加的值,进行排除。 
                        result.put(entry.getKey(), entry.getValue());
                    }
                }
            }
            return super.filterModel(result);
        }
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    上面提到的 MappingJackson2JsonView 我们已经在代码中使用了。 
    至于我还说到的 MappingJacksonValue 并不需要我们在哪里直接使用,其实 MappingJackson2JsonView 的源码中已经使用它做好了处理。我们只需要按上面说的在请求json的后面增加 jsonp 或 callback 参数即可。

    那么如果我们对于使用 @ResponseBody 注解直接响应JSON的该如何处理呢? 
    Follow Me ……

    原理: 
    ResponseBody 是通过 RequestResponseBodyMethodProcessor 来处理的,那我们就对这个类做一下包装处理。 
    RequestResponseBodyMethodProcessor 实现自接口 HandlerMethodReturnValueHandler,又因为Spring内部,同一个类型只能用一个的原则,我们实现自己的 HandlerMethodReturnValueHandler 实现类后,其中将原来的 RequestResponseBodyMethodProcessor 的原有对象包装进去,当我们完成自己的处理后,再讲处理权交给包装的 RequestResponseBodyMethodProcessor 对象。

    对 ResponseBody 还需要处理响应类型 (application/javascript) 
    在Spring内部,先从 ContentNegotiationStrategy 的方法 resolveMediaTypes 中读取 requestMediaTypes ,然后再去匹配 MappingJackson2HttpMessageConverter 中所有支持的 MediaTypes ,从而确定最终响应的 contentType。代码层面的处理也就是 ContentNegotiationStrategy 的 resolveMediaTypes 与 MappingJackson2HttpMessageConverter 的 getSupportedMediaTypes 结果对比处理。 
    为了满足我们JSONP的要求,requestMediaTypes 和 getSupportedMediaTypes 中都要包含 application/javascript

    所以我们还要做如下2步处理: 
    1、为 MappingJackson2HttpMessageConverter 添加 application/javascript 响应类型支持。 
    2、包装 ServletPathExtensionContentNegotiationStrategy ,重写 resolveMediaTypes 方法,根据JSONP特性 (callback参数),自动确定 application/javascript 请求类型。

    下面是代码: 
    其中 ResponseBodyWrapHandler 和 ContentNegotiationStrategyWrap 为包装类,ResponseBodyProcessor 为统一处理类。

    package org.springboot.sample.config.jsonp;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.MediaType;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
    import org.springframework.web.accept.ContentNegotiationManager;
    import org.springframework.web.accept.ContentNegotiationStrategy;
    import org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategy;
    import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
    import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
    
    /**
     * 处理Spring默认加载好的类,在原有类上使用自定义类进行包装处理。
     *
     * @author 单红宇(365384722)
     * @myblog http://blog.csdn.net/catoop/
     * @create 2016年2月29日
     */
    @Configuration
    public class ResponseBodyProcessor extends WebMvcConfigurerAdapter implements InitializingBean {
    
        @Autowired
        private RequestMappingHandlerAdapter adapter;
    
        @Autowired
        private ContentNegotiationManager manager;
    
        @Override
        public void afterPropertiesSet() throws Exception {
            List<HandlerMethodReturnValueHandler> returnValueHandlers = adapter.getReturnValueHandlers();
            List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(returnValueHandlers);
            decorateHandlers(handlers);
            adapter.setReturnValueHandlers(handlers);
    
            processContentNegotiationManager();
        }
    
        private void processContentNegotiationManager() {
            // 处理JSONP的响应ContentType
            List<ContentNegotiationStrategy> strategies = manager.getStrategies();
            for (int i = 0; i < manager.getStrategies().size(); i++) {
                if (manager.getStrategies().get(i) instanceof ServletPathExtensionContentNegotiationStrategy) {
                    strategies.set(i, new ContentNegotiationStrategyWrap(manager.getStrategies().get(i)));
                    manager = new ContentNegotiationManager(strategies);
                    break;
                }
            }
        }
    
        private void decorateHandlers(List<HandlerMethodReturnValueHandler> handlers) {
            for (HandlerMethodReturnValueHandler handler : handlers) {
                if (handler instanceof RequestResponseBodyMethodProcessor) {
                    // 用自己的ResponseBody包装类替换掉框架的,达到返回Result的效果
                    ResponseBodyWrapHandler decorator = new ResponseBodyWrapHandler(handler);
                    int index = handlers.indexOf(handler);
                    handlers.set(index, decorator);
                    break;
                }
            }
        }
    
        @Override
        public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
            for (HttpMessageConverter<?> httpMessageConverter : converters) {
                // 为 MappingJackson2HttpMessageConverter 添加 "application/javascript"
                // 支持,用于响应JSONP的Content-Type
                if (httpMessageConverter instanceof MappingJackson2HttpMessageConverter) {
                    MappingJackson2HttpMessageConverter convert = (MappingJackson2HttpMessageConverter) httpMessageConverter;
                    List<MediaType> medisTypeList = new ArrayList<>(convert.getSupportedMediaTypes());
                    medisTypeList.add(MediaType.valueOf("application/javascript;charset=UTF-8"));
                    convert.setSupportedMediaTypes(medisTypeList);
                    break;
                }
            }
            super.extendMessageConverters(converters);
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    package org.springboot.sample.config.jsonp;
    
    import java.util.Arrays;
    import java.util.LinkedHashSet;
    import java.util.Set;
    import java.util.regex.Pattern;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.core.MethodParameter;
    import org.springframework.http.converter.json.MappingJacksonValue;
    import org.springframework.util.StringUtils;
    import org.springframework.web.context.request.NativeWebRequest;
    import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
    import org.springframework.web.method.support.ModelAndViewContainer;
    
    /**
     * ResponseBody 处理类
     *
     * @author   单红宇(365384722)
     * @myblog  http://blog.csdn.net/catoop/
     * @create    2016年2月29日
     */
    public class ResponseBodyWrapHandler implements HandlerMethodReturnValueHandler{  
    
        protected final Log logger = LogFactory.getLog(getClass());
    
        private final HandlerMethodReturnValueHandler delegate;  
    
        private Set<String> jsonpParameterNames = new LinkedHashSet<String>(Arrays.asList("jsonp", "callback"));
    
        /**
         * Pattern for validating jsonp callback parameter values.
         */
        private static final Pattern CALLBACK_PARAM_PATTERN = Pattern.compile("[0-9A-Za-z_\.]*");
    
    
        private String getJsonpParameterValue(NativeWebRequest request) {
            if (this.jsonpParameterNames != null) {
                for (String name : this.jsonpParameterNames) {
                    String value = request.getParameter(name);
                    if (StringUtils.isEmpty(value)) {
                        continue;
                    }
                    if (!isValidJsonpQueryParam(value)) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Ignoring invalid jsonp parameter value: " + value);
                        }
                        continue;
                    }
                    return value;
                }
            }
            return null;
        }
    
        protected boolean isValidJsonpQueryParam(String value) {
            return CALLBACK_PARAM_PATTERN.matcher(value).matches();
        }
    
        public ResponseBodyWrapHandler(HandlerMethodReturnValueHandler delegate){  
          this.delegate=delegate;  
        }  
    
        @Override  
        public boolean supportsReturnType(MethodParameter returnType) {  
            return delegate.supportsReturnType(returnType);  
        }  
    
        @Override  
        public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {  
    
            String jsonpParameterValue = getJsonpParameterValue(webRequest);
            if (jsonpParameterValue != null) {
                if (!(returnValue instanceof MappingJacksonValue)) {
                    MappingJacksonValue container = new MappingJacksonValue(returnValue);
                    container.setJsonpFunction(jsonpParameterValue);
                    returnValue = container;
                }
            }
    
            delegate.handleReturnValue(returnValue,returnType,mavContainer,webRequest);  
        }  
    }  
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    package org.springboot.sample.config.jsonp;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.LinkedHashSet;
    import java.util.List;
    import java.util.Set;
    import java.util.regex.Pattern;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.http.MediaType;
    import org.springframework.util.StringUtils;
    import org.springframework.web.HttpMediaTypeNotAcceptableException;
    import org.springframework.web.accept.ContentNegotiationStrategy;
    import org.springframework.web.context.request.NativeWebRequest;
    
    /**
     * 对 ServletPathExtensionContentNegotiationStrategy 进行包装
     *
     * @author   单红宇(365384722)
     * @myblog  http://blog.csdn.net/catoop/
     * @create    2016年2月29日
     */
    public class ContentNegotiationStrategyWrap implements ContentNegotiationStrategy {
    
        protected final Log logger = LogFactory.getLog(getClass());
    
        private final ContentNegotiationStrategy strategy;
    
        private Set<String> jsonpParameterNames = new LinkedHashSet<String>(Arrays.asList("jsonp", "callback"));
    
        /**
         * Pattern for validating jsonp callback parameter values.
         */
        private static final Pattern CALLBACK_PARAM_PATTERN = Pattern.compile("[0-9A-Za-z_\.]*");
    
        private String getJsonpParameterValue(NativeWebRequest request) {
            if (this.jsonpParameterNames != null) {
                for (String name : this.jsonpParameterNames) {
                    String value = request.getParameter(name);
                    if (StringUtils.isEmpty(value)) {
                        continue;
                    }
                    if (!isValidJsonpQueryParam(value)) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Ignoring invalid jsonp parameter value: " + value);
                        }
                        continue;
                    }
                    return value;
                }
            }
            return null;
        }
    
        protected boolean isValidJsonpQueryParam(String value) {
            return CALLBACK_PARAM_PATTERN.matcher(value).matches();
        }
    
        public ContentNegotiationStrategyWrap(ContentNegotiationStrategy strategy) {
            super();
            this.strategy = strategy;
        }
    
        @Override
        public List<MediaType> resolveMediaTypes(NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
    
            // JSONP 响应类型处理 ---- BEGIN
            String jsonpParameterValue = getJsonpParameterValue(request);
            if (jsonpParameterValue != null) {
                List<MediaType> mediaTypes = new ArrayList<>(1);
                mediaTypes.add(MediaType.valueOf("application/javascript"));
                return mediaTypes;
            }
            // JSONP 响应类型处理 ---- END
    
            return this.strategy.resolveMediaTypes(request);
        }
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    然后新建一个PageController来测试下效果:

    @Controller
    public class PageController {
    
        private static final Logger log = LoggerFactory.getLogger(PageController.class);
    
        /**
         * 默认页<br/>
         * @RequestMapping("/") 和 @RequestMapping 是有区别的
         * 如果不写参数,则为全局默认页,加入输入404页面,也会自动访问到这个页面。
         * 如果加了参数“/”,则只认为是根页面。
         *
         * @return
         * @author SHANHY
         * @create  2016年1月5日
         */
        @RequestMapping(value = {"/","/index"})
        public String index(Map<String, Object> model){
            model.put("time", new Date());
            model.put("message", "小单,你好!");
    
            return "index";
        }
    
        /**
         * 响应到JSP页面page1
         *
         * @return
         * @author SHANHY
         * @create  2016年1月5日
         */
        @RequestMapping("/page1")
        public ModelAndView page1(){
            log.info(">>>>>>>> PageController.page1");
            // 页面位置 /WEB-INF/jsp/page/page.jsp
            ModelAndView mav = new ModelAndView("page/page1");
            mav.addObject("content", hello);
            return mav;
        }
    
        @RequestMapping("/testJson")
        @ResponseBody
        public Map<String, String> getInfo(@RequestParam(required=false) String name,
                @RequestParam(required=false) String name1) {
            Map<String, String> map = new HashMap<>();
            map.put("name", name);
            map.put("name1", name1);
            return map;
        }   
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    测试结果截图如下: 
    请求JSONP数据 
    这里写图片描述


    正常请求JSON数据 
    这里写图片描述


    直接请求显示页面 
    这里写图片描述


    至此,我们的服务端代码改造完毕,我们在 “不对原有业务代码进行任何修改的前提下” 完成了处理,接下来是在HTML页面中使用jQuery来请求JSONP实现跨域访问。

    将下面的代码存储为一个普通的HTML页面,然后用浏览器打开就可以测试了,当然别忘了启动你的web服务:

    <!DOCTYPE html> 
    <html> 
    <head> 
    <meta charset="utf-8"> 
    <script src="http://code.jquery.com/jquery-2.1.3.min.js"></script> 
    <script type="text/javascript"> 
    $(document).ready(function(){ 
    
        $("#b1").click(function(){ 
             $.ajax({ 
                url:'http://localhost:8080/myspringboot/testJson.json?name=Shanhy&name1=Lily', 
                type: "get", 
                async: false, 
                dataType: "jsonp", 
                jsonp: "callback", //服务端用于接收callback调用的function名的参数(请使用callback或jsonp)
                jsonpCallback: "fun_jsonpCallback", //callback的function名称
                success: function(json) { 
                    alert(json.name); 
                },
                error: function(){
                    alert('Request Error');
                } 
            }); 
        });        
    
        $("#b2").click(function(){ 
             $.ajax({ 
                url:'http://localhost:8080/myspringboot/testJson.json?name=Shanhy&name1=Lily', 
                type: "get", 
                async: false, 
                //dataType: "jsonp", 
                //jsonp: "callback", //服务端用于接收callback调用的function名的参数(请使用callback或jsonp)
                //jsonpCallback: "fun_jsonpCallback", //callback的function名称 
                success: function(json) { 
                    alert(json.name1); 
                },
                error: function(){
                    alert('Request Error');
                } 
            }); 
        });   
    
    }); 
    </script> 
    </head> 
    <body> 
    
        <div id="div1"><h2>jQuery AJAX 的跨域请求</h2></div> 
        <button id="b1">JSONP请求 (预期结果为成功)</button> <br/> 
        <button id="b2">JSON请求 (预期结果为失败)</button> 
    
    </body> 
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    至此,相信已经满足应用的需求,对部署容器不需要做任何修改。 
    不过还有另一种很简单的方法来支持Ajax的跨域请求,那就是在响应头中添加支持,如下:

    // 指定允许其他域名访问(必须)
    response.addHeader("Access-Control-Allow-Origin", "*");
    // 响应类型(非必须)
    response.addHeader("Access-Control-Allow-Methods", "POST");
    // 响应头设置(非必须)
    response.addHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果你前端使用到 ApacheServer、Nginx 那么也可以在他们的配置文件中直接配置,具体查一下资料即可。 
    这里有一点要注意:Access-Control-Allow-Origin 的 * 是允许所有,如果要针对域名设置,直接指定域名即可,但是请注意这里你不可以用逗号分割的方式同时配置多个域名。 
    如果你真的需要,可以参考如下代码:

            List<String> domainList = new ArrayList<>();
            domainList.add("http://www.domain1.com");
            domainList.add("http://www.domain2.com");
            domainList.add("http://localhost:8088");
            String requestDomain = request.getHeader("origin");
            log.info("requestDomain = " + requestDomain);
            if(domainList.contains(requestDomain)){
                response.addHeader("Access-Control-Allow-Origin", requestDomain);
                response.addHeader("Access-Control-Allow-Methods", "GET");
                response.addHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    实际应用中,根据自己的需要选择合适的方法。

    我喜欢开发者,程序猿。他们单纯、固执、容易体会到成就感;面对压力,能够挑灯夜战不眠不休;面对困难,能够迎难而上挑战自我。他们也会感到困惑与傍徨,但每个程序员的心中都有一个比尔盖茨或是乔布斯的梦想“用智慧开创属于自己的事业”。我想说的是,其实我是一个猿。
  • 相关阅读:
    模型驱动自动化测试框架
    TestPartner脚本错误处理的例子
    学习《Selenium 1.0 Testing Tools》
    自动化测试视频【持续更新】
    《软件测试基本功》系列教程
    自动化测试的误解与自动化测试的好处
    广州自动化测试实战训练系列课中的《QTP工具应用实战》课程PPT
    零基础QTP自动化测试训练
    Selenium结合FESTSwing测试Applet
    TestPartner自动化测试培训大纲
  • 原文地址:https://www.cnblogs.com/Garolli/p/5231111.html
Copyright © 2011-2022 走看看