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、DefaultCorsProcessorCorsUtils
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;
// 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 サイトの他の関連記事を参照してください。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









2023年、AI技術が注目を集め、プログラミング分野を中心にさまざまな業界に大きな影響を与えています。 AI テクノロジーの重要性に対する人々の認識はますます高まっており、Spring コミュニティも例外ではありません。 GenAI (汎用人工知能) テクノロジーの継続的な進歩に伴い、AI 機能を備えたアプリケーションの作成を簡素化することが重要かつ緊急になっています。このような背景から、AI 機能アプリケーションの開発プロセスを簡素化し、シンプルかつ直観的にし、不必要な複雑さを回避することを目的とした「SpringAI」が登場しました。 「SpringAI」により、開発者はAI機能を搭載したアプリケーションをより簡単に構築でき、使いやすく、操作しやすくなります。

Spring+AI は業界リーダーとして、強力で柔軟な API と高度な機能を通じてさまざまな業界に最先端のソリューションを提供します。このトピックでは、さまざまな分野での Spring+AI の応用例を詳しく掘り下げ、Spring+AI がどのように特定のニーズを満たし、目標を達成し、これらの教訓をより広範囲のアプリケーションに拡張するかを示します。このトピックが Spring+AI の無限の可能性をより深く理解し、活用するきっかけになれば幸いです。 Spring フレームワークはソフトウェア開発の分野で 20 年以上の歴史があり、Spring Boot 1.0 バージョンがリリースされてから 10 年が経過しました。今、その春に異論を唱える人はいない

Spring プログラムによるトランザクションを実装する方法: 1. TransactionTemplate を使用する; 2. TransactionCallback および TransactionCallbackWithoutResult を使用する; 3. Transactional アノテーションを使用する; 4. TransactionTemplate を @Transactional と組み合わせて使用する; 5. トランザクション マネージャーをカスタマイズする。

はじめに 今日の急速に進化するデジタル世界では、堅牢かつ柔軟で保守可能な WEB アプリケーションを構築することが重要です。 PHPmvc アーキテクチャは、この目標を達成するための理想的なソリューションを提供します。 MVC (Model-View-Controller) は、アプリケーションのさまざまな側面を独立したコンポーネントに分離する、広く使用されている設計パターンです。 MVC アーキテクチャの基礎 MVC アーキテクチャの核となる原則は、関心事の分離です。 モデル: アプリケーションのデータとビジネス ロジックをカプセル化します。ビュー: データの表示とユーザー インタラクションの処理を担当します。コントローラー: モデルとビュー間の対話を調整し、ユーザーのリクエストとビジネス ロジックを管理します。 PHPMVC アーキテクチャ phpMVC アーキテクチャは従来の MVC パターンに従いますが、言語固有の機能も導入しています。以下はPHPMVCです

Spring でトランザクション分離レベルを設定する方法: 1. @Transactional アノテーションを使用します; 2. Spring 構成ファイルに設定します; 3. PlatformTransactionManager を使用します; 4. Java 構成クラスに設定します。詳細な導入方法: 1. @Transactional アノテーションを使用し、トランザクション管理が必要なクラスまたはメソッドに @Transactional アノテーションを追加し、属性に分離レベルを設定します。 2. Spring の設定ファイルなどで

JUnit は Spring プロジェクトで広く使用されている Java 単体テスト フレームワークであり、次の手順で適用できます。 JUnit 依存関係を追加します。 org.junit.jupiterjunit-jupiter5.8.1test テスト ケースを作成します。 @ExtendWith(SpringExtension.class) を使用して拡張機能を有効にします。 @Autowired を使用して Bean を注入し、@BeforeEach と @AfterEach を使用して準備とクリーンアップを行い、テスト メソッドを @Test でマークします。

Spring は、Java 開発を簡素化し、強化するための多くのアノテーションを提供するオープンソース フレームワークです。この記事では、一般的に使用される Spring アノテーションについて詳しく説明し、具体的なコード例を示します。 @Autowired: Autowired @Autowired アノテーションを使用して、Spring コンテナーに Bean を自動的に接続できます。依存関係が必要な場合に @Autowired アノテーションを使用すると、Spring はコンテナー内で一致する Bean を見つけて自動的に注入します。サンプルコードは次のとおりです。

バックエンド管理システムでは、通常、さまざまなユーザーのインターフェイスへのアクセスを制限するために、アクセス許可制御が必要です。ユーザーに特定の権限がない場合、特定のインターフェイスにアクセスできません。この記事では、waynboot-mall プロジェクトを例として、一般的なバックエンド管理システムがアクセス許可制御フレームワーク SpringSecurity を導入する方法を紹介します。 waynboot-mall プロジェクトアドレス: https://github.com/wayn111/waynboot-mall 1. SpringSecurity とは SpringSecurity は、Spring フレームワークをベースとした、強力かつ柔軟なセキュリティの提供を目的としたオープンソース プロジェクトです。 Java アプリケーションの場合。
