簡介
CORS的全稱是跨域資源共享,他是一個基於HTTP-header檢測的機制,通過對HTTP-header進行控制,可以實現對跨域資源的許可權管理功能。在之前的CORS詳解文章中,我們已經對CORS有了基本的解釋。
本文將會從netty的實現角度,講解如何在netty中實現CORS。
服務端的CORS配置
熟悉CORS的朋友應該知道,CORS所有的操作都是在HTTP協議之上通過控制HTTP頭來實現的。所以說如果要在伺服器端實現CORS的支援,事實上也是對HTTP協議的頭進行各種設定完成的。
為了方便大家的使用,netty提供了一個CorsConfig類,來統一CORS的頭設定。
先看下CorsConfig類中定義的屬性:
private final Set<String> origins;
private final boolean anyOrigin;
private final boolean enabled;
private final Set<String> exposeHeaders;
private final boolean allowCredentials;
private final long maxAge;
private final Set<HttpMethod> allowedRequestMethods;
private final Set<String> allowedRequestHeaders;
private final boolean allowNullOrigin;
private final Map<CharSequence, Callable<?>> preflightHeaders;
private final boolean shortCircuit;
這些屬性和CORS的HTTP頭設定是一一對應的。比如說origins表示的是允許的源,anyOrigin表示允許所有的源。
是和下面的設定對應的:
Origin: <origin>
exposeHeaders是和Access-Control-Expose-Headers一一對應的,表示伺服器端允許客戶端獲取CORS資源的同時能夠訪問到的header資訊。其格式如下:
Access-Control-Expose-Headers: <header-name>[, <header-name>]*
allowCredentials表示是否開啟CORS的許可權認證。表示伺服器端是否接受客戶端帶有credentials欄位的請求。如果用在preflight請求中,則表示後續的真實請求是否支援credentials,其格式如下:
Access-Control-Allow-Credentials: true
allowedRequestMethods表示訪問資源允許的方法,主要用在preflight request中。其格式如下:
Access-Control-Allow-Methods: <method>[, <method>]*
allowedRequestHeaders用在preflight request中,表示真正能夠被用來做請求的header欄位,其格式如下:
Access-Control-Allow-Headers: <header-name>[, <header-name>]*
當客戶端傳送OPTIONS方法給伺服器的時候,為了安全起見,因為伺服器並不一定能夠接受這些OPTIONS的方法,所以客戶端需要首先傳送一個
preflighted requests,等待伺服器響應,等伺服器確認之後,再傳送真實的請求。我們舉一個例子。preflightHeaders表示的就是伺服器允許額preflight的請求頭。
shortCircuit表示請求是否是一個有效的CORS請求,如果請求被拒絕之後,就會返回一個true。
CorsConfigBuilder
CorsConfig使用來表示Cors的配置類,那麼怎麼去構造這個配置類呢?我們看下CorsConfig的建構函式:
CorsConfig(final CorsConfigBuilder builder) {
origins = new LinkedHashSet<String>(builder.origins);
anyOrigin = builder.anyOrigin;
enabled = builder.enabled;
exposeHeaders = builder.exposeHeaders;
allowCredentials = builder.allowCredentials;
maxAge = builder.maxAge;
allowedRequestMethods = builder.requestMethods;
allowedRequestHeaders = builder.requestHeaders;
allowNullOrigin = builder.allowNullOrigin;
preflightHeaders = builder.preflightHeaders;
shortCircuit = builder.shortCircuit;
}
可以看到CorsConfig是通過CorsConfigBuilder來構造的。通過設定CorsConfigBuilder中的各種屬性即可。CorsConfigBuilder中提供了多種設定屬性的方法。
可以使用這樣的方法來構造CorsConfig如下:
CorsConfig corsConfig = CorsConfigBuilder.forAnyOrigin().allowNullOrigin().allowCredentials().build();
CorsHandler
有了corsConfig,我們還需要將這個config配置在netty的handler中,netty提供了一個CorsHandler類來專門處理corsConfig,這個類就叫CorsHandler。
首先看下CorsHandler的建構函式:
public CorsHandler(final CorsConfig config) {
this(Collections.singletonList(checkNotNull(config, "config")), config.isShortCircuit());
}
public CorsHandler(final List<CorsConfig> configList, boolean isShortCircuit) {
checkNonEmpty(configList, "configList");
this.configList = configList;
this.isShortCircuit = isShortCircuit;
}
CorsHandler有兩個建構函式,一個是傳入CorsConfig,一個是傳入一個CorsConfig的列表。
CorsHandler的主要工作原理就是在channelRead的時候,對responseHeader進行處理,設定CORS頭。
netty對cors的支援
上面我們已經講過了netty中cors的核心類和方法,最後一步就是把cors的支援類加入到netty的pipeline中,其核心程式碼如下:
public void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new ChunkedWriteHandler());
CorsConfig corsConfig = CorsConfigBuilder.forAnyOrigin().allowNullOrigin().allowCredentials().build();
pipeline.addLast(new CorsHandler(corsConfig));
pipeline.addLast(new CustResponseHandler());
}
總結
cors比較簡單,netty也為其提供了住夠的方法支援。大家可以直接使用。
本文的例子可以參考:learn-netty4
本文已收錄於 http://www.flydean.com/22-netty-cors/
最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!