Spring Boot含特殊字符编码PathVariable时触发CORS错误求助
问题描述
在Spring Boot 2.7.1中实现了一个获取Entity详情的接口,通过@PathVariable从URI中获取ID,普通格式ID(如12345869)请求正常,但当使用RDF数据库的URI格式ID(如<http://www.semanticweb.org/blah/ontologies/2022/6/blah#12345869>,包含<、>、#等特殊字符)时,经JavaScriptencodeURIComponent编码后发起请求,Spring Boot返回CORS错误。
相关代码如下:
控制器代码
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.semdetect.server.entities.models.Entity; import com.semdetect.server.entities.services.EntityService; @RestController @RequestMapping("api/entity") public class EntityController { private final EntityService entityService; @Autowired public EntityController(EntityService entityService) { this.entityService = entityService; } @GetMapping("/{iri}") public Entity getEntityByIri(@PathVariable String iri) { System.out.println("In controller: " + iri); return this.entityService.getEntityByIri(iri); } }
CORS配置代码
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @SpringBootApplication public class ServerApplication { public static void main(String[] args) { SpringApplication.run(ServerApplication.class, args); } @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("http://localhost:4200"); } }; } }
POM配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.sem-detect</groupId> <artifactId>server</artifactId> <version>0.0.1-SNAPSHOT</version> <name>server</name> <description>Demo project for Spring Boot</description> <properties> <java.version>18</java.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.eclipse.rdf4j</groupId> <artifactId>rdf4j-bom</artifactId> <version>3.0.4</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.eclipse.rdf4j</groupId> <artifactId>rdf4j-client</artifactId> <type>pom</type> </dependency> <dependency> <groupId>org.eclipse.rdf4j</groupId> <artifactId>rdf4j-repository-sparql</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
解决方案
1. 调整路径匹配与Tomcat字符限制
Spring Boot 2.6+默认使用path_pattern_matcher,对路径中的特殊字符拦截较严格,同时Tomcat默认不允许部分特殊字符出现在路径中,需通过配置放开:
在application.properties中添加:
# 切换为宽松的Ant路径匹配器 spring.mvc.pathmatch.matching-strategy=ant_path_matcher # 允许路径中包含特殊字符 server.tomcat.relaxed-path-chars=<>#[]^`{} # 允许查询参数中包含特殊字符(按需添加) server.tomcat.relaxed-query-chars=<>#[]^`{}
2. 完善CORS配置,覆盖预检请求
编码后的特殊字符路径会触发浏览器的OPTIONS预检请求,原CORS配置未明确允许该方法,需补充:
修改CORS配置代码:
@Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:4200") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true); } }; }
3. 优化PathVariable的路径匹配规则
默认@PathVariable不会匹配路径中的斜杠,需通过正则表达式确保完整捕获URI格式的ID:
修改控制器的GetMapping注解:
@GetMapping("/{iri:.+}") public Entity getEntityByIri(@PathVariable(value = "iri", required = true) String iri) { System.out.println("In controller: " + iri); return this.entityService.getEntityByIri(iri); }
其中.+正则表示匹配任意字符(包括斜杠),确保完整获取编码后的URI内容。
4. 前端请求注意事项
确保前端使用encodeURIComponent对完整的URI进行编码,例如:
const iri = "<http://www.semanticweb.org/blah/ontologies/2022/6/blah#12345869>"; const encodedIri = encodeURIComponent(iri); fetch(`http://localhost:8080/api/entity/${encodedIri}`) .then(response => response.json()) .then(data => console.log(data));
内容的提问来源于stack exchange,提问作者whitefang1993
相关产品推荐
相关产品推荐

