フロントエンドとバックエンドの分離開発のクロスドメイン問題の概要
開発要件:
vue uniapp springboot を使用して WeChat アプレットを開発するプロセスでは、フロントエンドとバックエンドの分離モードも採用され、フロントエンド ページと JS は WeChat アプレットにデプロイされ、バックエンド インターフェイスはは Aliyun サーバーにデプロイされます。リクエストが開始されるとき、リクエストは同一オリジン ポリシーに準拠していないため、アクセスできません。クロスドメインの問題を解決し、フロントツーバックの対話を実現する必要があります。この記事では、クロスドメインの問題が発生する理由とその対処方法を体系的に紹介します。
1. クロスドメインアクセスとは
クロスドメイン アクセスについては、まず「同一オリジン ポリシー」という用語を理解する必要があります。
同一オリジンポリシーとは、ブラウザ側のセキュリティ上の理由から、サーバーへのリクエストは同じプロトコル、同じホスト (IP)、同じポートの条件を満たす必要があり、満たさない場合はアクセスが禁止され、そのアクセスは禁止されます。要件を満たしていない場合もブロックされます (クロスドメイン アクセスと呼ばれます)。
クロスドメインアクセスを禁止することで、アプリケーションのセキュリティはある程度向上しますが、開発に支障をきたすこともあります。
クロスドメインとは、ブラウザーが他の Web サイトからスクリプトを実行できないことを意味します。これは、JavaScript に対してブラウザーによって課されるセキュリティ制限です。
いわゆる同一オリジンとは、ドメイン名、プロトコル、ポートがすべて同じであることを意味します。例は次のとおりです。
http://www.jumper.com/index.html は http://www.jumper.com/server.PHP を呼び出します (非クロスドメイン)
http://www.jumper.com/index.html は http://www.sun.com/server.php を呼び出します (メインのドメイン名は異なります: Jumper/sun、クロスドメイン)
http://abc.jumper.com/index.html は http://def.jumper.com/server.php を呼び出します (異なるサブドメイン名: abc/def、クロスドメイン)
http://www.jumper.com:8080/index.html は http://www.jumper.com:8081/server.php を呼び出します (異なるポート: 8080/8081、クロスドメイン)
http://www.jumper.com/index.html は https://www.jumper.com/server.php を呼び出します (異なるプロトコル: http/https、クロスドメイン)
注意: localhost と 127.0.0.1 はどちらもローカル マシンを指しますが、クロスドメインでもあります。
2. クロスドメインの問題を解決する
クロスドメインの問題を解決するには、フロントエンドとバックエンドの 2 つの方法があり、バックエンドにはメソッドが含まれています。1 つのメソッドを使用でき、すべてを構成する必要はありません。
1. クロスドメインを解決するための Vue フロントエンド構成プロキシ
http://localhost:8080/users や http://localhost など、ブラウザによって送信される各リクエストで URL の前半が同じである必要があるため、Vue でクロスドメインの問題を解決するのは比較的簡単です。 :8080/ ログインの場合、同じ URL を抽出して にカプセル化できるaxios.defaults.baseURL
ため、リクエストするたびにリクエスト アドレスを「/users」と省略できます。これは、単純な URL ヘッダーのカプセル化を行うのと同じです。
リクエスト.js
import axios from 'axios'
const request = axios.create({
baseURL: '/api', // 这里是全局统一加上了 '/api' 前缀,也就是说所有接口都会加上'/api'前缀在,其他位置写接口的时候就不要加 '/api'了,否则会出现两个'/api',类似 '/api/api/user'这样的报错,切记!!!
timeout: 5000
})
// request 拦截器 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
// config.headers['token'] = user.token; // 设置请求头
return config
}, error => {
return Promise.reject(error)
});
// response 拦截器 可以在接口响应后统一处理结果
request.interceptors.response.use(
response => {
let res = response.data;
// 如果是返回的文件
if (response.config.responseType === 'blob') {
return res
}
// 兼容服务端返回的字符串数据
if (typeof res === 'string') {
res = res ? JSON.parse(res) : res
}
return res;
},
error => {
console.log('err' + error) // for debug
return Promise.reject(error)
}
)
export default request
view.config.js
module.exports = {
devServer: {
host: 'localhost',
open: true, // 自动打开浏览器
// 代理配置表,在这里可以配置特定的请求代理到对应的API接口
proxy: {
'/api': {
// 匹配所有以 '/api'开头的请求路径
target: 'http://localhost:8080', // 代理目标的基础路径
// secure: false, // 如果是https接口,需要配置这个参数
changeOrigin: true, // 支持跨域
pathRewrite: {
// 重写路径: 去掉路径中开头的'/api'
'^/api': ''
}
}
}
}
}
2. SpringBoot バックエンド構成はクロスドメインを解決します
2.1 クロスドメイン構成クラスCorsConfig
(よく使われるクラス)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
2.2コントローラに@CrossOrigin
アノテーションを追加する
@RestController
@RequestMapping("users/")
public class IndexController {
@GetMapping
@CrossOrigin
public String users() {
return "users";
}
}
2.3 CORSフィルターの追加CorsFilter
(よく使われる)
新しい構成クラス CorsFilterConfig を作成し、CorsFilter
フィルターを作成し、クロスドメインを許可します。
@Configuration
public class CorsConfig {
// 跨域请求处理
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
//允许所有域名进行跨域调用
config.addAllowedOrigin("*");
// config.addAllowedOrigin("http://localhost:8080");
//允许所有请求头
config.addAllowedHeader("*");
//允许所有方法
config.addAllowedMethod("*");
// 为url添加映射路径
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
2.4 Spring Security を使用してクロスドメインの問題を解決する
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and().cors().configurationSource(corsConfigurationSource())
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());//将csrf令牌存储在cookie中 允许cookie前端获取
}
CorsConfigurationSource corsConfigurationSource(){
CorsConfiguration config = new CorsConfiguration();
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("*"));
config.setAllowedOrigins(Arrays.asList("*"));
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}