• 解决ajax跨域几种方式


    发生跨域问题的原因:

    • 浏览器的限制,出于安全考虑。前台可以正常访问后台,浏览器多管闲事报跨域问题,但其实前台已经访问到后台了。

    • 跨域,协议、域名、端口任何一个不一样浏览器就认为是跨域。

    • XHR(XMLHttpRequest)请求,因为ajax是XHR请求,浏览器就会捕捉跨域问题。

    简单请求和非简单请求:

    • 简单请求 GET HEAD POST,请求header里面:无自定义头,Content-Type为以下几种:text/plain,multipart/form-data,application/x-www-form-urlencoded。

    • 非简单请求 put,delete方法的ajax请求,发送json格式的ajax请求,带自定义头的ajax请求。

    解决思路:

    • 让浏览器不做限制,指定参数,让浏览器不做校验,但该方法不太合理,它需要每个人都去做改动。

    • 不要发出XHR请求,这样就算是跨域,浏览器也不会报错,解决方案是JSONP,通过动态创建一个script,通过script发出请求。

    • 在跨域的角度:一种是被调用方修改代码,加上字段,告诉浏览器,支持跨域,支持调用。

    • 通过nginx代理方式,在a域名里面的的请求地址使用代理指定到b域名。

    跨域解决方案:

    • 被调用方解决:在请求响应头增加指定字段,告诉浏览器允许调用。这种解决方案的请求是直接从浏览器发送的。(服务器端实现、NGINX配置Apache配置)。

    • 调用方解决:这是隐藏跨域的解决法案。这种跨域请求不是直接从浏览器发送的,而是从中间的http服务器转发过去的。

    设置浏览器不做限制:

    • 可以使用everyting软件搜索浏览器的全路径,使用dos切换到此路径下 cd C:UsersAdministratorAppDataLocalGoogleChromeApplication

    • 输入 chrome --disable-web-security --user-data-dir=g: emp3(g磁盘 temp3数据存储文件可随便创建)。

    使用jsonp解决:

    • Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。为什么我们从不同的域(网站)访问数据需要一个特殊的技术(JSONP )呢?这是因为同源策略。同源策略,它是由Netscape提出的一个著名的安全策略,现在所有支持JavaScript 的浏览器都会使用这个策略。

    • 前端ajax方法请求设置 dataType: "jsonp"jsonp: "callback"cache: true

    • 后台需要增加JsonpAdvice 类

    • jsonp只支持GET
    • 服务器需要改动代码
    @ControllerAdvice
    public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
        public JsonpAdvice() {
            // TODO Auto-generated constructor stub
            // 这的名称需要和ajax中jsonp: "callback"设置的一样
            super("callback");
        }
    }
    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="UTF-8">
        <title>跨域</title>
        <script src="jquery-1.11.3.js"></script>
        <link rel="stylesheet" type="text/css" href="jasmine-2.8.0/jasmine.css">
        <script src="jasmine-2.8.0/jasmine.js"></script>
        <script src="jasmine-2.8.0/jasmine-html.js"></script>
        <script src="jasmine-2.8.0/boot.js"></script>
    </head>
    
    <body>
        <script>
            function get1() {
                    $.getJSON("http://localhost:8080/test/get1").then(function (result) {
                        console.log(result);
                    });
                }
                // 每一个测试用例的超时时间
            jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
             // 请求的接口的前缀 // http://localhost:8080/test
            var base = "/ajaxserverapache";
             //测试模块
            describe("跨域", function () {// 测试方法
                it("jsonp请求", function (done) {
                    // 服务器返回的结果
                    var result;
                    $.ajax({
                        url: base + "/get1",
                        dataType: "jsonp",
                        jsonp: "callback",
                        cache: true,
                        success: function (json) {
                            result = json;
                        }
                    });
                    // 由于是异步请求,需要使用setTimeout来校验
                    setTimeout(function () {
                        expect(result).toEqual({
                            "data": "get1 ok"
                        });
    
                        // 校验完成,通知jasmine框架
                        done();
                    }, 100);
                });
            });
        </script>
    </body>
    
    </html>

    filter解决方案(被调用方):

    • 在springBoot启动类中设置filter类过滤

    • 设置具体的过滤参数信息

    @SpringBootApplication
    public class AjaxserverApplication {
        public static void main(String[] args) {
            SpringApplication.run(AjaxserverApplication.class, args);
        }
    
        @Bean
        public FilterRegistrationBean registerFilter() {
            FilterRegistrationBean bean = new FilterRegistrationBean();
            bean.addUrlPatterns("/*");
            //  设置自定义的filter类
            bean.setFilter(new CrosFilter());
            return bean;
        }
    }
    public class CrosFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // TODO Auto-generated method stub
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
            // TODO Auto-generated method stub
            HttpServletResponse res = (HttpServletResponse) response;
    
            HttpServletRequest req = (HttpServletRequest) request;
    
            String origin = req.getHeader("Origin");
    
            if (!org.springframework.util.StringUtils.isEmpty(origin)) {
                //带cookie的时候,origin必须是全匹配,不能使用*
                res.addHeader("Access-Control-Allow-Origin", origin);
            }
    
            res.addHeader("Access-Control-Allow-Methods", "*");
            String headers = req.getHeader("Access-Control-Request-Headers");
    
            // 支持所有自定义头
            if (!org.springframework.util.StringUtils.isEmpty(headers)) {
                res.addHeader("Access-Control-Allow-Headers", headers);
            }
         // 设置预检命令一小时内不需要再发送 res.addHeader(
    "Access-Control-Max-Age", "3600"); // enable cookie res.addHeader("Access-Control-Allow-Credentials", "true"); chain.doFilter(request, response); } @Override public void destroy() { // TODO Auto-generated method stub } }

     nginx解决方案(被调用方):

    • 在nginx文件中创建一个挂载文件夹vhost(创建a.conf配置文件)

    • 在nginx.conf配置文件中引入vhost文件夹下conf结尾的配置文件    include vhost/*.conf;

    • 配置如下(nginx -t检测配置文件是否正确   之后重载配置文件 nginx -s reload)
    server{
        listen 80;
        server_name a.com;
        
        location /{
            proxy_pass http://localhost:8080/;
            
            add_header Access_Control-Allow-Methods *;
            add_header Access_Control-Max-Age 3600;
            add_header Access_Control-Allow-Credentials true;
            add_header Access_Control-Allow-Origin $http_origin; 
            add_header Access_Control-Allow-Headers
            $http_access_control_request_headers;
            
            if ($request_method = OPTIONS){
                # 判断是否是预检命令
                return 200;
            }
        }
    }

     Apache服务解决:

    • 打开Apache24confhttpd.conf配置文件

    • 放开注释的配置:

    • LoadModule vhost_alias_module modules/mod_vhost_alias.so

    • Include conf/extra/httpd-vhosts.conf

    • LoadModule proxy_module modules/mod_proxy.so

    • LoadModule proxy_http_module modules/mod_proxy_http.so

    • LoadModule headers_module modules/mod_headers.so

    • LoadModule rewrite_module modules/mod_rewrite.so

    • 打开Apache24confextrahttpd-vhosts.conf配置文件,在最下边添加配置

    • 重启服务
    <VirtualHost *:80>
        ServerName a.com
        ErrorLog "logs/a.com-error.log"
        CustomLog "logs/a.com-access.log" common
        ProxyPass /http://localhost:8080/
        
        # 把请求头的origin值返回到Access-Control-Allow-Origin字段
        Header always set Access-Control-Allow-Origin 'expr=%{req:origin}'
    
        # 把请求头的Access-Control-Allow-Headers值返回到Access-Control-Allow-Headers字段
        Header always set Access-Control-Allow-Headers "expr=%{req:Access-Control-Request-Headers}"
    
        Header always set Access-Control-Allow-Methods "*"
        Header always set Access-Control-Allow-Credentials "true"
        Header always set Access-Control-Max-Age "3600"
    
        #处理预检命令
        RewriteEngine On
        RewriteCond %{REQUEST_METHOD}OPTIONS
        RewriteRule ^(.*)$"/" [R=204,L]
    </VirtualHost>

    spring解决:

    • String 框架解决方案: @CrossOrigin  注解添加类上面

     

    被调用方隐藏跨域解决Apache服务解决:

      打开Apache24confextrahttpd-vhosts.conf配置文件,在最下边添加配置

    重启服务

    <VirtualHost *:80>
        ServerName a.com
        ErrorLog "logs/a.com-error.log"
        CustomLog "logs/a.com-access.log" common
        
        #被调用方接口
        ProxyPass /ajaxserverapache   http://localhost:8080/test
        #调用方
        ProxyPass /http://localhost:8081/
    </VirtualHost>

    被调用方隐藏跨域解决nginx:

    • 在nginx文件中创建一个挂载文件夹vhost(创建a.conf配置文件)

    • 在nginx.conf配置文件中引入vhost文件夹下conf结尾的配置文件    include vhost/*.conf;

    • 页面中接口访问前缀替换成下配置的相对路径/ajaxserver

    • 配置如下(nginx -t检测配置文件是否正确   之后重载配置文件 nginx -s reload)

    server{
        listen 80;
        server_name a.com;
        
        location /{
           # 调用方
            proxy_pass http://localhost:8081/;
        }
        
         location /ajaxserver{
            # 被调用方接口
            proxy_pass http://localhost:8080/test;
        }
    } 
  • 相关阅读:
    LeetCode 209. 长度最小的子数组(Minimum Size Subarray Sum)
    LeetCode 快乐数(Happy Number)
    Deep & Cross Network总结
    CTR预估之LR与GBDT融合
    近似最近邻算法-annoy解析
    FM与FFM深入解析
    LeetCode 222. 完全二叉树的节点个数(Count Complete Tree Nodes)
    js 时间与时间戳的转换
    table 样式美化
    c# string 和 byte[]数组之间转换
  • 原文地址:https://www.cnblogs.com/haha66/p/12004178.html
Copyright © 2020-2023  润新知