天天看點

CORS跨域-Nginx使用方法(Access-Control-Allow-Origin錯誤提示)

#問題說明

CORS跨域-Nginx使用方法(Access-Control-Allow-Origin錯誤提示)

當出現上圖這個的時候,是通路請求外域URL無法通路,浏覽器認為通路外域URL不安全,導緻通路不了簡稱跨域問題。而這上面出現一句很重要的話“NO Access-Control-Allow-Origin”,這個是什麼?是不是隻要添加“Access-Control-Allow-Origin”頭就能通路呢?如何添加?會不會有其他問題?

Access-Control-Allow-Origin 表示允許通路的外域 URI

例子:

Access-Control-Allow-Origin: http://www.a.com

允許通路www.a.com站點

Access-Control-Allow-Origin: *

“*”允許通路任何外域URL

這個是由服務端那邊設定的,讓服務端告知浏覽器允許這個站點通路。那就是說隻要設定了這個參數,那就能跨域了。而這種跨域方式也就叫CORS。

CORS是一個W3C标準,全稱是"跨域資源共享"(Cross-origin resource sharing)。

它允許浏覽器向跨源伺服器,發出XMLHttpRequest請求,進而克服了AJAX隻能同源使用的限制。本文就是談CORS技術實作。

#技術介紹

當我們出現跨域提示的時候,其實我們已經向伺服器已經完成一次發送和接收請求(請求是發送連接配接的url)。伺服器接收請求後通知浏覽器,告訴浏覽器不能通路外域站點。浏覽器會顯示不能通路原因,顯示通路外域失敗。

而CORS就是在伺服器上,設定Response Headers 傳回參數Access-Control-Allow-Origin,Access-Control-Allow-Headers,Access-Control-Allow-Methods,讓站點能通路外域。

CORS跨域-Nginx使用方法(Access-Control-Allow-Origin錯誤提示)
參數 說明
Control-Allow-Origin 表示允許通路的外域請求。
Access-Control-Allow-Headers 首部字段用于預檢請求的響應。其指明了實際請求中允許攜帶的首部字段。
Access-Control-Allow-Methods 首部字段用于預檢請求的響應。其指明了實際請求所允許使用的 HTTP 方法。

##簡單請求(能不能不發送options)

在正式跨域的請求前,浏覽器會根據需要,發起一個“PreFlight”(也就是Option請求),用來讓服務端傳回允許的方法(如get、post),被跨域通路的Origin(來源,或者域),還有是否需要Credentials(認證資訊)

三種場景:

如果跨域的請求是Simple Request(簡單請求 ),則不會觸發“PreFlight”。Mozilla對于簡單請求的要求是:

以下三項必須都成立:

  1. 隻能是Get、Head、Post方法
  2. 除了浏覽器自己在Http頭上加的資訊(如Connection、User-Agent),開發者隻能加這幾個:Accept、Accept-Language、Content-Type、。。。。
  3. Content-Type隻能取這幾個值:

    application/x-www-form-urlencoded

    multipart/form-data

    text/plain

##如何操作

1.看到下圖我們發送請求的時候 在Request Headers 中Origin:http://www.a.com,Origin是我們目前站點URL域名。

CORS跨域-Nginx使用方法(Access-Control-Allow-Origin錯誤提示)
CORS跨域-Nginx使用方法(Access-Control-Allow-Origin錯誤提示)

2.Nginx伺服器接收後會檢視是不是配置CORS,如果是檢視配置的域名是不是比對如下圖:http://www.a.com,比對允許這個站點通路。

CORS跨域-Nginx使用方法(Access-Control-Allow-Origin錯誤提示)

3.使用CORS發送請求,第一個請求會是"OPTIONS"這個是設定傳回頭并且傳回成功。之後會自動再發一個post/get請求,成功發送到伺服器。這樣代碼以及可以成功跨域了。

CORS跨域-Nginx使用方法(Access-Control-Allow-Origin錯誤提示)
CORS跨域-Nginx使用方法(Access-Control-Allow-Origin錯誤提示)

4.最後在看一下Response Headers 發現Access-Control-Allow-Origin設定http://www.a.com的域名了。代表已經成功設定好CORS了。

CORS跨域-Nginx使用方法(Access-Control-Allow-Origin錯誤提示)

##相容性

pc相容ie8以上,手機端上随意用。如果想相容更低版本浏覽器請使用JSONP或者Nginx做代理。

CORS跨域-Nginx使用方法(Access-Control-Allow-Origin錯誤提示)

#Nginx配置代碼 在Nginx中的nginx.cof中添加下面代碼就可以實作CORS跨域了。

set $origin '*';#寫入需要跨域的請求位址
if ($request_method = 'OPTIONS') {
	add_header 'Access-Control-Allow-Origin' $origin;
	add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
	add_header 'Access-Control-Max-Age' 1728000;
	add_header 'Content-Type' 'text/plain charset=UTF-8';
	add_header 'Content-Length' 0;
	return 204;
}

if ($request_method = 'POST') {
	add_header 'Access-Control-Allow-Origin' $origin;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}

if ($request_method = 'GET') {
    add_header 'Access-Control-Allow-Origin' $origin;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
           

#Springboot配置代碼

@Configuration
public class CorsConfig {
    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        // 設定你要允許的網站域名,如果全允許則設為 *
        config.addAllowedOrigin("http://localhost:4200");
        // 如果要限制 HEADER 或 METHOD 請自行更改
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        // 這個順序很重要哦,為避免麻煩請設定在最前
        bean.setOrder(0);
        return bean;
    }
}
           

#Node express配置代碼

var app = express();

//設定跨域通路
app.all('*', function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", ' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
});
app.listen(6064);
           

繼續閱讀