• No 'AccessControlAllowOrigin' header is present之跨域问题及解决方案


     如图,是在chome浏览器的Console中显示的信息,很明显,No 'Access-Control-Allow-Origin' header is present on the requested resource这句话表示出现了跨域请求问题,那么什么是跨域请求呢?

    一、何为“跨域”?

         跨域是浏览器对于javascript的同源策略的限制,一般我们使用ajax发送请求时会出现这种情况,举个栗子:A网站有一个请求路径为http:ip1:port1/aa,我们希望使用Ajax来获得B网站中的特定内容。而B网站的域名地址为http:ip2:prot2,只要ip和port有一个不一致,那么就出现了跨域访问问题。你可以理解为两个域名之间不能跨过域名来发送请求或者请求数据,否则就是不安全的。跨域访问违反了同源策略,同源策略规定,浏览器的ajax只能访问跟它的HTML页面同源(相同域名或IP)的资源。

    在讲跨域解决方案时,我们先来探讨一下http请求类型及浏览器发送跨域请求过程

      http请求一般常见的有GET,POST,请求header里面无自定义头,Content-Type为以下几种:text/plain  multipart/form-data application/x-www-form-urlencoded。此外还有非简单请求如put delete的ajax请求,发送json格式的ajax请求,带自定义头的ajax请求。

    如果是简单请求,浏览器会先发送请求,然后判断服务器返的返回头中是否支持跨域请求,否则抛出跨域异常

    如果是非简单请求,浏览器会先发出OPTIONS请求方法的检测命令,判断服务器是否支持跨域请求,如果支持则发送真正的请求,如果不支持则抛出跨域异常,因此一个非简单请求每次会发送两个请求
    跨域解决方案一般有以下几种:

    一、JSONP方式

    jsonp 全称是JSON with Padding,是为了解决跨域请求资源而产生的解决方案,是一种依靠开发人员创造出的一种非官方跨域数据交互协议。一个是描述信息的格式,一个是信息传递双方约定的方法。

    jsonp的产生:

    1.AJAX直接请求普通文件存在跨域无权限访问的问题,不管是静态页面也好.

    2.不过我们在调用js文件的时候又不受跨域影响,比如引入jquery框架的,或者是调用相片的时候

    3.凡是拥有scr这个属性的标签都可以跨域例如<script><img><iframe>

    4.如果想通过纯web端跨域访问数据只有一种可能,那就是把远程服务器上的数据装进js格式的文件里.

    5.而json又是一个轻量级的数据格式,还被js原生支持

    6.为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback 参数给服务端,

    注意:使用JSONP方式实现跨域请求只能是get请求不能使用post请求

    不多说,直接上代码

    function testJSONPAPI() {
            $.ajax({
                type: "POST",
                async: true,
                dataType: "jsonp",
                jsonp:"callback",
                data: {
                    userName:"aaaaa"
                },
                url: "http://172.16.15.90:8080/user/getUserByJSONP",
                success: function (data) {
                    console.log(data);
                    
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    
                }
            });
        }
    

      后端代码:

    @ResponseBody
        @RequestMapping(value = "/getUserByJSONP", method = RequestMethod.GET)
        public String getMySeatSuccess(@RequestParam("callback") String callback, String userName) {
            Gson gson = new Gson();
            Map<String, String> map = new HashMap<>();
            map.put("userName", userName);
            return callback + "(" + gson.toJson(map) + ")";
        }


    需要注意的是:前端注意与后端沟通约定jsonp的值,通常默认都是用callback。后端根据jsonp参数名获取到参数后要与本来要返回的json数据按“callback(json)”的方式构造。

    二、服务端通过filter或者interceptor解决跨域

       既然No 'Access-Control-Allow-Origin' header is present,那我们就在服务端对所有跨域的请求url做一个拦截,在拦截器里动态添加上允许跨域请求就OK了,

    下面是最简单的一个允许跨域请求的拦截器

    public class RemoteInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse resp, Object handler) throws Exception {
    //        resp.addHeader("Access-Control-Allow-Origin","*");
            resp.setHeader("Access-Control-Allow-Origin","*");
            resp.setCharacterEncoding("UTF-8");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    
        }
    }

    三、通过springboot自带配置类中去配置

    @Configuration
    @EnableWebMvc
    @ComponentScan({"com.example.demo.controller", "com.example.demo.interceptors"})
    public class WebConfig extends WebMvcConfigurerAdapter {
    
        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new RemoteInterceptor()).addPathPatterns("/**");
        }
    
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**").allowedOrigins("*");
        }
    }
    少一些浮躁,多一份坚持,专注技术,砥砺前行。
  • 相关阅读:
    为什么无法从外部访问VSTO对象?
    通过实例代码理解WPF的Dispatcher
    Silverlight打印解决方案2.0之如何自定义表体
    VSTO"无法加载自定义程序集"
    打开silverlight项目之前,您需要安装最新的Silverlight Developer运行时
    Android 3.2 联机测试adb驱动如何安装和配置?
    Android 3.2 应用程序联机(devices)测试失败提示INSTALL_FAILED_INSUFFICIENT_STORAGE
    Android sdk 3.0 sdk3.1 sdk3.2 平板开发环境安装日志
    android 蓝牙开发常见问题总结
    Pad本蓝牙模块检测
  • 原文地址:https://www.cnblogs.com/guoft-share/p/10594236.html
Copyright © 2020-2023  润新知