記事ディレクトリ
実際のプロジェクトでは、フロントエンドとバックエンドが 2 つの異なるプロジェクトに分割され、それぞれが異なるドメイン名でデプロイされるため、クロスドメインの問題も発生します。
問題が発生したので、問題を根本的に解決する必要がありますが、解決策について話す前に、クロスドメインとは何かを理解する必要があります。
クロスドメインとは何ですか?
クロスドメインとは、ブラウザーが他の Web サイトからのスクリプトを実行できないことを意味します。これは、ブラウザーの同一生成元ポリシー (JavaScript に対してブラウザーによって課されるセキュリティ制限) が原因で発生します。
同一生成元ポリシーとは何ですか?
いわゆる相同性とは、プロトコル、ドメイン名、ポート番号がすべて同じであるが、そのうちの 1 つが異なる限り、それらはすべて同じ起源ではないことを指します。
同一オリジン ポリシーは、Netscape によって提案されたセキュリティ ポリシーです。これはブラウザの中核であり、最も基本的なセキュリティ機能です。同一オリジン ポリシーが存在しない場合、ブラウザの通常の機能に影響が出る可能性があります。現在、サポートされているすべてのブラウザが対応しています。 JavaScript はこの戦略を使用します。
ブラウザはスクリプトを実行するときに、そのスクリプトがどのページに属しているか、つまり同じオリジンのものであるかどうかをチェックし、同じオリジンのスクリプトのみが実行されます。同じオリジンではないスクリプトがリクエストした場合は、データが存在しない場合、ブラウザは例外を報告し、アクセスの拒否を促します。
-
http://www.a.com/index.html
呼び出しhttp://www.a.com/user.jsp
プロトコル、ドメイン名、およびポート番号はすべて同じであり、発行元も同じです。 -
https://www.a.com/index.html
呼び出しhttp://www.a.com/user.jsp
プロトコルは異なり、同じ起源のものではありません。 -
http://www.a.com:8080/index.html
呼び出しhttp://www.a.com:8081/user.jsp
ポートは異なっており、同じ発信元ではありません。 -
http://www.a.com/index.html
呼び出し元のhttp://www.b.com/user.jsp
ドメイン名は異なり、同じ起源のものではありません。 -
http://localhost:8080/index.html
呼び出しhttp://127.0.0.1:8080/user.jsp
localhost は 127.0.0.1 に相当しますが、発信元が同じではありません。
同一生成元ポリシーによって制限される状況:
-
Cookie、LocalStorage、IndexDB を読み取れません
-
DOMおよびJsオブジェクトが取得できない
-
AJAXリクエストを送信できませんでした
注: img、iframe、script などのタグの src 属性は特殊なケースであり、同じ生成元ではない Web サイトのリソースにアクセスできます。
クロスドメインプロセス
クロスドメインアクセスの例
2 つの Web サイトがあり、Web サイト A はhttp://localhost:8080
ローカル IP ポート 8080 に展開され、Web サイト B はhttp://localhost:8081
ローカル IP ポート 8081 に展開されているとします。
Web サイト B のページが Web サイト A の情報にアクセスしたいとすると、ページは次のように表示されます。
上記のエラー メッセージから、クロスドメインの問題が発生していることがわかります。
クロスドメインの問題を解決するにはどうすればよいでしょうか?
1.フィルター
Filter フィルターを使用してサービス リクエストをフィルター処理し、応答ヘッダー (応答ヘッダー) の Access-Control-Allow-Origin 属性をリクエスタに設定して、クロスドメイン アクセスが許可されていることを宣言します。
@WebFilter
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(req, res);
}
}
2. HandlerInterceptorAdapterの継承
@Component
public class CrossInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
return true;
}
}
3. WebMvcConfigurer を実装する
@Configuration
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
public class AppConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 拦截所有的请求
.allowedOrigins("http://www.abc.com") // 可跨域的域名,可以为 *
.allowCredentials(true)
.allowedMethods("*") // 允许跨域的方法,可以单独配置
.allowedHeaders("*"); // 允许跨域的请求头,可以单独配置
}
}
4. Nginx 構成を使用する
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
if ($request_method = 'OPTIONS') {
return 204;
}
}
5.@CrossOrgin
注釈を使用する
一部のインターフェイスのみをドメイン間で共有し、構成を使用して管理したくない場合は、この方法を使用できます。
コントローラーでの使用
@CrossOrigin
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/{id}")
public User get(@PathVariable Long id) {
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
}
}
特定のインターフェイスで使用する
@RestController
@RequestMapping("/user")
public class UserController {
@CrossOrigin
@GetMapping("/{id}")
public User get(@PathVariable Long id) {
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
}
}
要約する
フロントエンドソリューション
- JSONP を使用してクロスドメイン呼び出しを実装します。
- NodeJS サーバーをサービス プロキシとして使用し、フロントエンドが NodeJS サーバーへのリクエストを開始し、NodeJS サーバー プロキシがそのリクエストをバックエンド サーバーに転送します。
バックエンドソリューション
- Nginx リバースプロキシはクロスドメインを解決します
- サーバー設定
Response Header
(応答ヘッダー)Access-Control-Allow-Origin
。 @CrossOrigin
クロスドメイン アクセスを必要とするクラスおよびメソッドでクロスドメイン アクセスを許可します ( Spring でのアノテーションの使用など)。- Spring Web の CorsFilter (Spring MVC、Spring Boot に適用) を継承して使用します。
- WebMvcConfigurer インターフェイスを実装します (Spring Boot 用)。