検索
ホームページJava&#&チュートリアルSpring MVC cors クロスドメイン実装ソースコードのサンプルコード分析

この記事では主にSpring MVC corsのクロスドメイン実装のソースコード解析を紹介します。非常に優れた参考値です。以下のエディターで見てみましょう

用語の説明: Cross-Origin Resource Sharing

簡単に言うと、プロトコル、IP、httpメソッドが異なっていれば、クロスドメインです。

spring MVC は 4.2 以降、クロスドメインのサポートを追加しました。

クロスドメインの具体的な定義については、mozilla にアクセスして

ユースケース

Spring MVC でクロスドメインを使用するには 3 つの方法があります:

Web で CorsFilter を構成する注釈を使用して xml で構成された .xml

<filter>
 <filter-name>cors</filter-name>
 <filter-class>org.springframework.web.filter.CorsFilter</filter-class>
</filter>
<filter-mapping>
 <filter-name>cors</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>

// 简单配置,未配置的均使用默认值,就是全面放开
<mvc:cors> 
 <mvc:mapping path="/**" /> 
</mvc:cors> 
// 这是一个全量配置
<mvc:cors> 
 <mvc:mapping path="/api/**" 
  allowed-origins="http://domain1.com, http://www.php.cn/" 
  allowed-methods="GET, PUT" 
  allowed-headers="header1, header2, header3" 
  exposed-headers="header1, header2" allow-credentials="false" 
  max-age="123" /> 
  <mvc:mapping path="/resources/**" 
  allowed-origins="http://domain1.com" /> 
</mvc:cors>

ee

関連する概念

CorsConfiguration はポジョです特にクロスドメイン構成情報をカプセル化します

  • CorsConfigurationSource リクエストとクロスドメイン構成情報をマッピングするためのコンテナ

  • 特定のクロスドメイン操作用の CorsProcessor クラス

  • Nuogan クロスドメイン構成情報初期化クラス

  • クロスドメイン使用のためのNuoganアダプター

  • 関与するJavaクラス:

情報をカプセル化するpojo

CorsConfiguration

リクエストとクロスドメイン設定情報を保存するコンテナ

CorsConfigurationSource、URLBasedCorsConfigurationSource

特定の処理クラス

CorsProcessor、DefaultCorsProcessor

CorsUtils

OncePerRequestFilterインターフェースを実装

CorsFilter

リクエストがcorsであるかどうかを確認し、対応するアダプター

AbstractHandlerMapping (内部を含む) class PreFlightHandler、CorsInterceptor

CrossOriginアノテーション情報の読み取り

AbstractHandlerMethodMapping、RequestMappingHandlerMapping

xmlファイルからのクロスドメイン構成情報の読み取り

CorsBeanDefinitionParser

クロスドメインの登録補助クラス

MvcNamespaceUtils

debug分析

必要なコードを理解するには、まずクロスドメイン情報をカプセル化する pojo を理解しましょう -- CorsConfiguration

これは、クロスドメインに対応するいくつかのプロパティに加えて、combined、checkOrigin だけです。 、checkHttpMethod、およびcheckHeaders。 属性は複数の値と組み合わせて使用​​されます。

@CrossOrigin(maxAge = 3600) 
@RestController 
@RequestMapping("/account") 
public class AccountController { 
 @CrossOrigin("http://domain2.com") 
 @RequestMapping("/{id}") 
 public Account retrieve(@PathVariable Long id) { 
  // ... 
 } 
}

combine は、クロスドメイン情報をマージすることです

3 つのチェック方法は、リクエスト内の情報が許可された範囲に含まれているかどうかをチェックすることです

設定の初期化

が、システムが開始され、構成ファイルを解析します。RequestMappingHandlerMapping をロードするときに、InitializingBean の afterProperties フックを通じて initCorsConfiguration を呼び出し、アノテーション情報を初期化します。

構成ファイルの初期化

CorsBeanDefinitionParser クラスの parse メソッドにブレークポイントを置きます。

CorsBeanDefinitionParserのコールスタック

ここでコードを通して解析を確認できます

クロスドメイン情報の構成では、パス単位で複数のマッピング関係を定義できます。

解析中に定義がない場合は、デフォルト設定が使用されます

 // CorsConfiguration
 public static final String ALL = "*";
 // 允许的请求源
 private List<String> allowedOrigins;
 // 允许的http方法
 private List<String> allowedMethods;
 // 允许的请求头
 private List<String> allowedHeaders;
 // 返回的响应头
 private List<String> exposedHeaders;
 // 是否允许携带cookies
 private Boolean allowCredentials;
 // 预请求的存活有效期
 private Long maxAge;

解析が完了したら、MvcNamespaceUtils.registerCorsConfiguratoions を通じて登録します

ここでは Spring Bean コンテナ管理の統一プロセスに従います。 BeanDefinition に変換されてインスタンス化されます。

// CorsBeanDefinitionParser
if (mappings.isEmpty()) {
 // 最简配置时的默认设置
 CorsConfiguration config = new CorsConfiguration();
 config.setAllowedOrigins(DEFAULT_ALLOWED_ORIGINS);
 config.setAllowedMethods(DEFAULT_ALLOWED_METHODS);
 config.setAllowedHeaders(DEFAULT_ALLOWED_HEADERS);
 config.setAllowCredentials(DEFAULT_ALLOW_CREDENTIALS);
 config.setMaxAge(DEFAULT_MAX_AGE);
 corsConfigurations.put("/**", config);
}else {
 // 单个mapping的处理
 for (Element mapping : mappings) {
  CorsConfiguration config = new CorsConfiguration();
  if (mapping.hasAttribute("allowed-origins")) {
   String[] allowedOrigins = StringUtils.tokenizeToStringArray(mapping.getAttribute("allowed-origins"), ",");
   config.setAllowedOrigins(Arrays.asList(allowedOrigins));
  }
  // ...
 }

アノテーションの初期化

RequestMappingHandlerMappingのinitCorsConfiguration内のCrossOriginアノテーションが付けられたメソッドをスキャンして情報を抽出します。

RequestMappingHandlerMapping_initCorsConfiguration

// MvcNamespaceUtils
 public static RuntimeBeanReference registerCorsConfigurations(Map<String, CorsConfiguration> corsConfigurations, ParserContext parserContext, Object source) {
  if (!parserContext.getRegistry().containsBeanDefinition(CORS_CONFIGURATION_BEAN_NAME)) {
   RootBeanDefinition corsConfigurationsDef = new RootBeanDefinition(LinkedHashMap.class);
   corsConfigurationsDef.setSource(source);
   corsConfigurationsDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
   if (corsConfigurations != null) {
    corsConfigurationsDef.getConstructorArgumentValues().addIndexedArgumentValue(0, corsConfigurations);
   }
   parserContext.getReaderContext().getRegistry().registerBeanDefinition(CORS_CONFIGURATION_BEAN_NAME, corsConfigurationsDef);
   parserContext.registerComponent(new BeanComponentDefinition(corsConfigurationsDef, CORS_CONFIGURATION_BEAN_NAME));
  }
  else if (corsConfigurations != null) {
   BeanDefinition corsConfigurationsDef = parserContext.getRegistry().getBeanDefinition(CORS_CONFIGURATION_BEAN_NAME);   
   corsConfigurationsDef.getConstructorArgumentValues().addIndexedArgumentValue(0, corsConfigurations);
  }
  return new RuntimeBeanReference(CORS_CONFIGURATION_BEAN_NAME);
 }

クロスドメインリクエスト処理

HandlerMapping 検索プロセッサを正常に処理した後、AbstractHandlerMapping.getHandlerでクロスドメインリクエストであるかどうかを確認します。 2回で完了します処理:

事前リクエストの場合は、プロセッサを内部クラス PreFlightHandler に置き換えます

通常のリクエストの場合は、CorsInterceptor インターセプターを追加します

    拿到处理器后,通过请求头是否包含Origin判断是否跨域,如果是跨域,通过UrlBasedCorsConfigurationSource获取跨域配置信息,并委托getCorsHandlerExecutionChain处理

    UrlBasedCorsConfigurationSource是CorsConfigurationSource的实现,从类名就可以猜出这边request与CorsConfiguration的映射是基于url的。getCorsConfiguration中提取request中的url后,逐一验证配置是否匹配url。

     // UrlBasedCorsConfigurationSource
     public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
      String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
      for(Map.Entry<String, CorsConfiguration> entry : this.corsConfigurations.entrySet()) {
       if (this.pathMatcher.match(entry.getKey(), lookupPath)) {
        return entry.getValue();
       }
      }
      return null;
     }
     // AbstractHandlerMapping
     public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
      Object handler = getHandlerInternal(request);
      // ...
      HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
      if (CorsUtils.isCorsRequest(request)) {
       CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
       CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
       CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
       executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
      }
      return executionChain;
     }
     // HttpHeaders
     public static final String ORIGIN = "Origin";
     // CorsUtils
     public static boolean isCorsRequest(HttpServletRequest request) {
      return (request.getHeader(HttpHeaders.ORIGIN) != null);
     }

    通过请求头的http方法是否options判断是否预请求,如果是使用PreFlightRequest替换处理器;如果是普通请求,添加一个拦截器CorsInterceptor。

    PreFlightRequest是CorsProcessor对于HttpRequestHandler的一个适配器。这样HandlerAdapter直接使用HttpRequestHandlerAdapter处理。

    CorsInterceptor 是CorsProcessor对于HnalderInterceptorAdapter的适配器。

     // AbstractHandlerMapping
     protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
       HandlerExecutionChain chain, CorsConfiguration config) {
      if (CorsUtils.isPreFlightRequest(request)) {
       HandlerInterceptor[] interceptors = chain.getInterceptors();
       chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
      }
      else {
       chain.addInterceptor(new CorsInterceptor(config));
      }
      return chain;
     }
     private class PreFlightHandler implements HttpRequestHandler {
      private final CorsConfiguration config;
      public PreFlightHandler(CorsConfiguration config) {
       this.config = config;
      }
      @Override
      public void handleRequest(HttpServletRequest request, HttpServletResponse response)
        throws IOException {
    
       corsProcessor.processRequest(this.config, request, response);
      }
     }
     private class CorsInterceptor extends HandlerInterceptorAdapter {
      private final CorsConfiguration config;
      public CorsInterceptor(CorsConfiguration config) {
       this.config = config;
      }
      @Override
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
        Object handler) throws Exception {
    
       return corsProcessor.processRequest(this.config, request, response);
      }
     }
     // CorsUtils
     public static boolean isPreFlightRequest(HttpServletRequest request) {
      return (isCorsRequest(request) && request.getMethod().equals(HttpMethod.OPTIONS.name()) &&
        request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD) != null);
     }


    以上がSpring MVC cors クロスドメイン実装ソースコードのサンプルコード分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    高度なJavaプロジェクト管理、自動化の構築、依存関係の解像度にMavenまたはGradleを使用するにはどうすればよいですか?高度なJavaプロジェクト管理、自動化の構築、依存関係の解像度にMavenまたはGradleを使用するにはどうすればよいですか?Mar 17, 2025 pm 05:46 PM

    この記事では、Javaプロジェクト管理、自動化の構築、依存関係の解像度にMavenとGradleを使用して、アプローチと最適化戦略を比較して説明します。

    適切なバージョン化と依存関係管理を備えたカスタムJavaライブラリ(JARファイル)を作成および使用するにはどうすればよいですか?適切なバージョン化と依存関係管理を備えたカスタムJavaライブラリ(JARファイル)を作成および使用するにはどうすればよいですか?Mar 17, 2025 pm 05:45 PM

    この記事では、MavenやGradleなどのツールを使用して、適切なバージョン化と依存関係管理を使用して、カスタムJavaライブラリ(JARファイル)の作成と使用について説明します。

    カフェインやグアバキャッシュなどのライブラリを使用して、Javaアプリケーションにマルチレベルキャッシュを実装するにはどうすればよいですか?カフェインやグアバキャッシュなどのライブラリを使用して、Javaアプリケーションにマルチレベルキャッシュを実装するにはどうすればよいですか?Mar 17, 2025 pm 05:44 PM

    この記事では、カフェインとグアバキャッシュを使用してJavaでマルチレベルキャッシュを実装してアプリケーションのパフォーマンスを向上させています。セットアップ、統合、パフォーマンスの利点をカバーし、構成と立ち退きポリシー管理Best Pra

    キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPA(Java Persistence API)を使用するにはどうすればよいですか?キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPA(Java Persistence API)を使用するにはどうすればよいですか?Mar 17, 2025 pm 05:43 PM

    この記事では、キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPAを使用することについて説明します。潜在的な落とし穴を強調しながら、パフォーマンスを最適化するためのセットアップ、エンティティマッピング、およびベストプラクティスをカバーしています。[159文字]

    Javaのクラスロードメカニズムは、さまざまなクラスローダーやその委任モデルを含むどのように機能しますか?Javaのクラスロードメカニズムは、さまざまなクラスローダーやその委任モデルを含むどのように機能しますか?Mar 17, 2025 pm 05:35 PM

    Javaのクラスロードには、ブートストラップ、拡張機能、およびアプリケーションクラスローダーを備えた階層システムを使用して、クラスの読み込み、リンク、および初期化が含まれます。親の委任モデルは、コアクラスが最初にロードされ、カスタムクラスのLOAに影響を与えることを保証します

    See all articles

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    AI Hentai Generator

    AI Hentai Generator

    AIヘンタイを無料で生成します。

    ホットツール

    MinGW - Minimalist GNU for Windows

    MinGW - Minimalist GNU for Windows

    このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

    WebStorm Mac版

    WebStorm Mac版

    便利なJavaScript開発ツール

    SecLists

    SecLists

    SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

    Dreamweaver Mac版

    Dreamweaver Mac版

    ビジュアル Web 開発ツール

    Safe Exam Browser

    Safe Exam Browser

    Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。