springboot 解決跨域請求,No 'Access-Control-Allow-Origin' header is present on the requested resource
springboot 解決跨域請求,No 'Access-Control-Allow-Origin' header is present on the requested resource
================================
©Copyright 蕃薯耀 2020-11-24
https://www.cnblogs.com/fanshuyao/
跨域請求,一般是在頁面呼叫ajax請求向別的服務傳送請求,因域名不相同,導致跨域
解決跨域請求的方式有:
一、遠端伺服器支援跨域請求(CORS 跨域)
二、使用nginx反向代理
三、伺服器端使用Http請求
四、使用jsonp
下面以遠端伺服器支援跨域請求(CORS 跨域)為例:
其中有三種方式讓遠端伺服器支援跨域請求
方式一、使用註解:@CrossOrigin
1、在類上加註解,表示類下所有方法都支援跨域請求
@CrossOrigin @RestController @RequestMapping("cross") public class AaaController { }
2、在方法加註解,表示該方法運動跨域請求
@RestController @RequestMapping("cross") public class AaaController { @CrossOrigin @RequestMapping("/bbb") public Result bbb(HttpServletRequest request, HttpServletResponse response) throws Exception { …… } }
方式二、實現WebMvcConfigurer介面,重寫addCorsMappings方法(官方文件全域性配置跨域請求使用的是此方式)
import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.test.util.JsonUtil; @Configuration public class MvcConfig implements WebMvcConfigurer { /** * 解決跨域請求 * @return */ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowCredentials(true) .allowedOrigins("*") .allowedHeaders("*") .allowedMethods("*") .maxAge(3600); WebMvcConfigurer.super.addCorsMappings(registry); } /** * 解決@RestController返回json結果時,IE瀏覽器出現下載json檔案的現象。 * @return */ @Bean public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() { MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(); List<MediaType> supportedMediaTypes = new ArrayList<MediaType>(); supportedMediaTypes.add(new MediaType(MediaType.TEXT_PLAIN, Charset.forName("UTF-8"))); supportedMediaTypes.add(new MediaType(MediaType.TEXT_HTML, Charset.forName("UTF-8"))); jsonConverter.setSupportedMediaTypes(supportedMediaTypes); jsonConverter.setObjectMapper(JsonUtil.getMapper());//設定使用jackson轉換器 return jsonConverter; } @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(jackson2HttpMessageConverter()); } }
方式三、使用CorsFilter過濾器
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; @Configuration public class HttpFilterConfig { @Bean public FilterRegistrationBean<CorsFilter> corsFilter() { CorsConfiguration corsConfig = new CorsConfiguration(); corsConfig.setAllowCredentials(true); corsConfig.addAllowedOrigin(CorsConfiguration.ALL); corsConfig.addAllowedMethod(CorsConfiguration.ALL); corsConfig.addAllowedHeader(CorsConfiguration.ALL); //預設可不設定這個暴露的頭。這個為了安全問題,不能使用*。設定成*,後面會報錯:throw new IllegalArgumentException("'*' is not a valid exposed header value"); //corsConfig.addExposedHeader(""); corsConfig.setMaxAge(3600L); UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(); configSource.registerCorsConfiguration("/**", corsConfig); FilterRegistrationBean<CorsFilter> corsBean = new FilterRegistrationBean<CorsFilter>(new CorsFilter(configSource)); corsBean.setName("crossOriginFilter"); corsBean.setOrder(0);//這個順序也有可能會有影響,儘量設定在攔截器前面 return corsBean; } }
前端頁面呼叫示例:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>跨域請求</title> <script type="text/javascript" src="js/jquery-3.4.1.min.js"></script> </head> <body> <div>跨域請求</div> <script type="text/javascript"> function ajax(){ console.log("ajax()"); $.ajax({ //async: false,//設定為同步,預設為非同步(一般不需要) url : "http://aaa.com:7010/gtkjCghj/workflow/processes", //aaa.com域名修改host檔案 type : "post", dataType : "json", //contentType: "application/json;charset=UTF-8",//contentType如果設定成application/json;charset=UTF-8,就會會變成複雜請求,導致傳送2次請求,第一次是options請求,第二次才是真正的請求。 data : { "processName" : "報批", "gxDocNo": "f2-202000234", "ssotoken":"eyJpc3N1Y2Nlc3MiOiJ0cnVlIiwiZmFpbHJlc29uIjoiIiwiYWNjb3VudCI6Inplbmd6aW0iLCJ0b2tlbiI6ImE5YzA5YTdjYWRlOTQwNjFiNzdmYzMxNjhkZDI2Mzc3In0=.Eg4DFhERDQ==" }, complete : function(XMLHttpRequest, textStatus){ //alert("textStatus="+textStatus); }, error : function(XMLHttpRequest, textStatus, errorThrown){ if("error" == textStatus){ alert("伺服器未響應,請稍候再試"); }else{ alert("請求失敗,textStatus="+textStatus); } }, success : function(data){ if(data != null){ console.log("data===" + JSON.stringify(data)); }else{ alert("返回結果為空!"); } } }); }; ajax(); </script> </body> </html>
需要注意的是ajax請求中的contentType:
contentType預設的值是:application/x-www-form-urlencoded,當不設定或者為預設值時,這個是簡單請求,只發送1次真正的請求。
如果contentType設定成"application/json;charset=UTF-8"會變成複雜請求,導致傳送2次請求,第一次是options請求,第二次才是真正的請求。部分伺服器,是禁止傳送OPTIONS請求的,這樣會導致跨域問題:
jquery-3.4.1.min.js:2 OPTIONS http://test.com/gtkjCghj/workflow/processes 401 (Unauthorized)
has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
================================
©Copyright 蕃薯耀 2020-11-24
https://www.cnblogs.com/fanshuyao/