在Spring MVC中进行CORS设置
首先 or 开始
这篇文章总结了在使用Angular和Spring Boot进行SPA开发时,将客户端和服务器端应用程序托管在不同机器上时需要考虑的事项。
-
- Same Origin Policy
-
- Cross-Origin Resource Sharing
-
- Spring MVC の Cross-Origin Resource Sharing 設定
- サーバホスト名解決
我将以以下的四个结构进行解释。
顺便说一句,我们已经发布了应用程序的示例。
同源策略
被翻译为“同一起源政策”。
以下是下面的图表:
-
- Angular アプリが https://angular.example.com
Spring Boot アプリが https://boot.example.com
这表示它们在各自运行。
在Web浏览器中,访问https://angular.example.com,
下载index.html和js文件,
在Web浏览器中运行Angular应用程序。
在这种情况下,客户端会使用Spring Boot运行的服务器https://boot.example.com进行数据获取的异步通信,但该请求会出现错误。
因此,通过应用同源策略,可以限制从https://angular.example.com加载的脚本文件无法访问https://boot.example.com资源。
这被称为同源策略(Same Origin Policy)。
跨源资源共享
CORS 是跨域资源共享的缩写。
同源策(Same Origin Policy)是构建安全的Web应用程序的重要概念。
然而,当客户端和服务器端需要在不同的机器上运行时,就需要使用跨域资源共享(Cross-Origin Resource Sharing,也称为跨域资源共享)来实现。
基本机制涉及HTTP请求头和HTTP响应头之间的交互。
首先,客户端会设置一个名为”Origin”的请求头并发送请求。该值将被设置为脚本文件的来源,即”https://angular.example.com”。
Origin: https://angular.example.com
然后,服务器接收到请求后,将判断请求头中的Origin值是否合法。
如果合法,服务器将在返回时附加Access-Control-Allow-Origin响应头,并正常返回响应。
Access-Control-Allow-Origin: https://angular.example.com
请参考 MDN web docs 上的“跨源资源共享(CORS)”获取更详细的信息。
Spring MVC 的跨域资源共享设置
Spring MVC 可以轻松配置跨域资源共享。
本次的配置是什么呢?
-
- コントローラークラス・メソッドに個別にアノテーションで設定する
- Java Configでアプリケーション全体で設定する
我将向您介绍两种方法。
另外,为了简化环境搭建,假设您使用Spring Boot。
在控制器类的方法上单独使用注解进行设置。
我們使用@CrossOrigin註釋。
實際的使用方法如下:
package com.example.server.web.rest;
import com.example.server.service.TaskService;
import com.example.server.web.response.TaskResponse;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/tasks")
public class TaskRestController {
private final TaskService todoService;
public TaskRestController(TaskService todoService) {
this.todoService = todoService;
}
@GetMapping
@CrossOrigin
public List<TaskResponse> findAll() {
return this.todoService.findAll().stream().map(todo -> new TaskResponse(todo)).collect(Collectors.toList());
}
}
給控制器方法添加標註以允許來自不同來源的存取。這樣做可以啟用跨源資源共享。(给控制器方法添加注解以允许来自不同来源的访问。这样做可以启用跨源资源共享。)
但是,默认设置下,允许的源是通配符,也就是允许从全球任何网站生成的脚本发出请求的设置。
您可以使用@CrossOrigin注释的origins属性来设置允许的Origin。
以下给出了具体的方法。
package com.example.server.web.rest;
import com.example.server.service.TaskService;
import com.example.server.web.response.TaskResponse;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/tasks")
public class TaskRestController {
private final TaskService todoService;
public TaskRestController(TaskService todoService) {
this.todoService = todoService;
}
@GetMapping
@CrossOrigin(origins = {"http://localhost:4200"})
public List<TaskResponse> findAll() {
return this.todoService.findAll().stream().map(todo -> new TaskResponse(todo)).collect(Collectors.toList());
}
}
由于接收到的是字符串数组,因此可以设置多个允许的Origin。
请参考官方文档并进行适当的设置,因为还可以施加其他详细的限制。
用Java Config在整个应用程序中进行配置设定。
让我们删除先前在控制器方法中设置的@CrossOrigin注解。
请将下面的Java配置放在Spring Boot的组件扫描有效包中。
package com.example.server.web.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:4200");
}
}
WebMvcConfigurer是一个用于自定义Spring Web相关配置的接口。
通过添加@Configuration注解并将其配置为Java Config,可以重写方法来自定义配置。
CORS通过addCorsMappings方法将参数CorsRegistry进行设置。
在上述的例子中,原点(Origin)允许接收来自 http://localhost:4200 的设置。
由于可以进行更详细的设置,请参考官方文档并根据要求进行配置。
服务器主机名解析
如果要处理CORS,那么在开发环境中需要
只需要一种选项:在本地环境中运行的话,生产环境中会例如。
需要考虑在运行的环境中的差异。换句话说,开发环境的Angular应用程序需要切换到http://localhost:8080进行异步通信,而生产环境的Angular应用程序需要切换到https://boot.example.com。
由于Angular可以具有特定于环境的配置值,因此我们可以利用它。
在Angular应用程序中,默认情况下,在src/environments目录下有各个环境的配置文件。
-
- environment.ts :開発環境用
- environment.prod.ts :本番環境用
这是配置文件。
默认情况下,
export const environment = {
production: false
};
export const environment = {
production: true
};
只有这个被设定。
我将编辑为下列形式。
export const environment = {
production: false,
apiUrl: 'http://localhost:8080'
};
export const environment = {
production: true,
apiUrl: 'http://boot.example.com'
};
我們將添加 apiUrl 的設定。
因為 production 用於判定是否以開發模式啟動 Angular 應用程式,所以保留它。
接下來,我們將編輯用於執行非同步通訊請求的服務類別。
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs';
import {Task} from './task';
import {environment} from "../environments/environment";
@Injectable({
providedIn: 'root'
})
export class TaskDataService {
constructor(private http: HttpClient) {
}
findAll(): Observable<Task[]> {
return this.http.get<Task[]>(environment.apiUrl + '/api/tasks');
}
}
将异步通信的请求URL从环境设置文件中引用。
在使用Angular CLI的ng serve进行执行或者使用无选项的ng build进行构建时,
将应用开发环境的environment.ts应用,
但是如果使用ng build –prod并带有生产环境选项进行构建,
将应用生产环境的environment.prod.ts。
请参考参考书 获取更详细的信息。
只需要一個選項,請把以下內容用中文重述:
充分
補齊
-
- Angular CLI :Angularアプリの開発をサポートするコマンドライン
-
- ng serve :Angular CLIに含まれるAngularアプリの検証サーバ
- ng build :Angular CLIに含まれるAngularアプリのビルド機能