解決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:\Users\Administrator\AppData\Local\Google\Chrome\Application

  • 輸入 chrome --disable-web-security --user-data-dir=g:\temp3(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服務解決:

  • 打開Apache24\conf\httpd.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

  • 打開Apache24\conf\extra\httpd-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服務解決:

  打開Apache24\conf\extra\httpd-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;
    }
} 


免責聲明!

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



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