因此,我正在使用Springtoolsuite创建Restful Web服务,也正在创建Rest Client。我现在可以运行该服务,并让Postman既给我期望的结果,又运行内部的Spring浏览器并进行适当的操作。
但是,如果我随后在Springs浏览器之外加载html文件,却在Mozilla和Chrome中遇到“ CORS请求未成功”和“ CORS预检通道未成功”的典型CORS错误,则得到403的OPTIONS和CORS策略已阻止从来源“空”访问“ http://localhost:8080/ ..处的XMLHttpRequest。”:对预检请求的响应未通过访问控制检查:没有“ Access-Control-Allow-Origin”头存在于请求的资源上。”这也是CORS问题。
localhost:8080是我选择的URL,因为当我将项目作为Spring Boot应用程序运行时,Apache Tomcat在此端口上启动服务。
我现在不确定的是如何找出我在Rest Client中发出的措辞不佳的请求,还是我的服务器代码出现问题,例如,据说错误可能来自多次预检,所以我不确定我可能正在这样做。
首先是服务器代码:
package de.TeamCAM.textory.rest_interface;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.Authorization;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import multex.Exc;
import static multex.MultexUtil.create;
import de.TeamCAM.textory.domain.*;
import de.TeamCAM.textory.domain.imports.*;
@CrossOrigin(origins = "http://localhost:8080")
@RestController
@Transactional
public class ApplicationController {
private final KapitelRepository kapitelRepository;
private final String className = getClass().getSimpleName();
@Autowired
public ApplicationController(final KapitelRepository kapitelRepository) {
this.kapitelRepository = kapitelRepository;
}
@GetMapping(path = "/Kategorie/Welt/Kapitel/{kapitelname}")
public ResponseEntity<KapitelResource> findeEinKapitel(@PathVariable String kapitelname,
@ApiParam(hidden = true) final HttpMethod method, final WebRequest request, HttpServletResponse res) {
_print(method, request);
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "*");
final Kapitel kapitel;
kapitel = kapitelRepository.find(kapitelname);
if(kapitel != null) {
return new ResponseEntity<>(new KapitelResource(kapitel), HttpStatus.OK);}
else return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@RequestMapping(method = RequestMethod.OPTIONS, value="/**")
public void manageOptions(HttpServletResponse response)
{
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
} }
这是处理请求的Apllicationcontroller。我也有一个安全类,我尝试以某种方式修改安全类,以解决所有可能性和CORS问题。
package de.TeamCAM.textory.rest_interface;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String CLIENT_ROLE = "CLIENT";
private static final String BANK_ROLE = "BANK";
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/**").permitAll()
.antMatchers("/bank/**").hasRole(BANK_ROLE)
.antMatchers("/client/**").hasRole(CLIENT_ROLE)
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers(HttpMethod.OPTIONS, "file:///E:/se2/spring-ddd-bank/src/main/resources/static/kapitel.html").permitAll()
.antMatchers(
HttpMethod.GET,
"/v2/api-docs",
"/swagger-resources/**",
"/swagger-ui.html**",
"/webjars/**",
"favicon.ico"
).permitAll()
.anyRequest().authenticated()
.and().httpBasic()
.and().csrf().disable()
;
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET","POST","OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
private static final List<String> predefinedUsernames = Arrays.asList("bank", "hans", "nina", "fritz", "lisa");
@Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
final InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication = auth.inMemoryAuthentication();
for(final String username: predefinedUsernames) {
final String role = username.equalsIgnoreCase(BANK_ROLE) ? BANK_ROLE : CLIENT_ROLE;
inMemoryAuthentication.withUser(username).password(username).roles(role);
}
}
public List<String> predefinedUsernames(){
return predefinedUsernames;
}
}
另外根据另一个stackoverflow答案,我创建了另一个类来添加cors支持
package de.TeamCAM.textory.rest_interface;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}`
这也没有帮助,我还根据其他答案添加了一些依赖项,现在我的pom.xml如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<name>Spring DDD Bank</name>
<groupId>de.bht-berlin.knabe</groupId>
<artifactId>spring-ddd-bank</artifactId>
<version>0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<aspectj.version>1.8.9</aspectj.version>
<derby.version>10.12.1.1</derby.version>
<multexVersion>8.3</multexVersion>
<swagger.version>2.8.0</swagger.version>
<messageTextFile>MessageText.properties</messageTextFile>
</properties>
<dependencies>
<!-- Experiment Knabe 2018-11-15: Serve Web Content, see https://spring.io/guides/gs/serving-web-content/ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- According to https://spring.io/guides/gs/rest-hateoas/ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<!-- According to https://spring.io/guides/gs/securing-web/ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Derby Database (in-memory in test suite, or in-directory in production
code) -->
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
</dependency>
<!-- For offering the Derby network server when the REST server is running: -->
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbynet</artifactId>
<version>${derby.version}</version>
</dependency>
<!-- For downloading the Derby Client Driver: -->
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbyclient</artifactId>
<version>${derby.version}</version>
<!-- Install artifact into the local repo, so that a database browser
can pick it up, but do not deliver it with the product: -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.tfh-berlin.knabe</groupId>
<artifactId>multex</artifactId>
<version>${multexVersion}</version>
</dependency>
<!-- Following http://www.mojohaus.org/aspectj-maven-plugin/usage.html -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- Disable Maven Compiler Plugin for production sources following https://stackoverflow.com/questions/14614446/how-do-i-disable-the-maven-compiler-plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<!-- Use AspectJ Maven Plugin instead for compiling production sources
following http://www.mojohaus.org/aspectj-maven-plugin/usage.html -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<goals>
<goal>compile</goal> <!-- use this goal to weave all your main classes -->
</goals>
</execution>
</executions>
<configuration>
<complianceLevel>${java.version}</complianceLevel>
<source>${java.version}</source>
<target>${java.version}</target>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<dependencies>
<!-- Avoid AspectJ version clashes between 1.8.9 and 1.8.10 following
https://stackoverflow.com/questions/41646801/maven-aspectj-weaving-for-java8 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<!-- Here used for extraction of exception message texts in the reference
language from the exception Javadoc comments. -->
<goals>
<goal>javadoc</goal>
</goals>
<!-- <phase>process-classes</phase> -->
<phase>compile</phase>
<configuration>
<!-- Specific configuration for the messages report -->
<doclet>multex.tool.ExceptionMessagesDoclet</doclet>
<docletArtifact>
<groupId>de.tfh-berlin.knabe</groupId>
<artifactId>multex</artifactId>
<version>${multexVersion}</version>
</docletArtifact>
<useStandardDocletOptions>false</useStandardDocletOptions>
<show>private</show>
<verbose>false</verbose>
<debug>false</debug>
<additionalparam>
-out
${project.build.directory}/classes/${messageTextFile}
</additionalparam>
<!-- For the project-reports page -->
<name>ExceptionTexts</name>
<description>Extraction of Exception Message Texts from Source
Code</description>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<!-- Java Code Coverage analyzer. See https://www.petrikainulainen.net/programming/maven/creating-code-coverage-reports-for-unit-and-integration-tests-with-the-jacoco-maven-plugin/ -->
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
<executions>
<!-- Prepares the property pointing to the JaCoCo runtime agent, which
is passed as VM argument, when the Maven Surefire plugin is executed. -->
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<!-- Sets the path to the file which contains the execution data. -->
<destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile>
<!-- Sets the name of the property containing the settings for the
JaCoCo runtime agent. -->
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
<!-- Ensures that the code coverage report for unit tests is created
after unit tests have been run. -->
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<!-- Sets the path to the file which contains the collected execution
data. -->
<dataFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</dataFile>
<!-- Sets the output directory for the code coverage report. -->
<outputDirectory>${project.reporting.outputDirectory}/jacoco-ut</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- Sets the VM argument line for test runs in Surefire, created by
the upper prepare-agent goal of the jacoco-maven-plugin. -->
<argLine>${surefireArgLine}</argLine>
</configuration>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-javadoc-plugin
</artifactId>
<versionRange>
[2.9.1,)
</versionRange>
<goals>
<goal>javadoc</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-dependency-plugin
</artifactId>
<versionRange>
[3.0.2,)
</versionRange>
<goals>
<goal>sources</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<configuration>
<show>private</show>
</configuration>
</plugin>
<!-- Do not look for possible repositories for each dependency in order
to speed up project site generation. See https://www.mkyong.com/maven/maven-site-build-is-very-slow-dependency-report/ -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.9</version>
<configuration>
<dependencyLocationsEnabled>false</dependencyLocationsEnabled>
</configuration>
</plugin>
</plugins>
</reporting>
<repositories>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository><!-- For current MulTEx: -->
<id>bht-knabe-repository</id>
<name>BHT Knabe Maven 2 repository</name>
<url>http://public.beuth-hochschule.de/~knabe/mvn-repo/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
我是在没有web.xml文件的情况下执行此操作的,因此,有关如何更改web.xml以添加CORS支持的所有答案当然也没有帮助。我认为,服务器端的所有这些都会使CORS支持或停止对CORS的支持。
html几乎没有害处,唯一相关的行是
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="allstar.js" defer></script>
我在脑海中,把它们放在身体的尽头并没有改变。 这两个相关的js文件如下:
let speichern = document.getElementById("speichern");
var put = document.getElementById("put");
var dele = document.getElementById("delete");
var post = document.getElementById("post");
var get = document.getElementById("get");
let form = document.getElementById("formSubmit");
let kapitelName = document.getElementsByName("kapitelName")[0];
let kapitelInhalt = document.getElementsByName("kapitelInhalt")[0];
let istEnde = document.getElementById("istEnde");
let bild = document.getElementsByName("bild");
let name = {};
let inhalt = {};
kapitelName.oninput = function() {
name.value = kapitelName.value;
console.log(name);
}
kapitelInhalt.oninput = function() {
inhalt.value = kapitelInhalt.value;
console.log(inhalt);
}
istEnde.onchange = function() {
console.log("The checkbox was checked.");
}
var script = document.createElement('script');
script.onload = function () {}
document.getElementById("put").onclick = function() {
myputFunction()
}
function myputFunction() {
script.src = "trueput.js";
document.head.appendChild(script);
}
document.getElementById("get").onclick = function() {
mygetFunction()
}
function mygetFunction() {
script.src = "trueget.js";
document.head.appendChild(script);
}
document.getElementById("post").onclick = function() {
mypostFunction()
}
function mypostFunction() {
script.src = "truepost.js";
document.head.appendChild(script);
}
document.getElementById("delete").onclick = function() {
mydeleteFunction()
}
function mydeleteFunction() {
script.src = "truedelete.js";
document.head.appendChild(script);
}
处理不同按钮上的buttonclicks并启动相应的js文件。我在applicationcontroller和每个文件中都有POST PUT和DELETE方法,但是我至少希望得到一个GET并从那里继续。因此,这是GET请求的JS文件,该文件正进行其余交换的整个客户端:
var kapitelname = document.getElementsByClassName("titelanzeige")[0].value;
$.ajax({
headers: {
'Authorization': 'Basic ' + btoa("bank" + ":" + "bank")
},
url: "http://localhost:8080/Kategorie/Welt/Kapitel/" +kapitelname,
type: 'GET',
success: function(data) {
$('.titelanzeige').html("");
$('.inhaltsanzeige').html("");
$('.titelanzeige').append(data.kapitelname);
$('.inhaltsanzeige').append(data.inhalt);
}
});
我尝试将Origin:添加到此,但是它没有被识别,只会出现一个错误。将类型更改为text或json并没有实现任何目的。因此,在为服务器和客户端实施了一系列解决方案之后,我仍然受到相同来源策略的阻碍,我的主要问题是如何检查这两个方面中的哪一个有问题,以便我知道该怎么做上。提前致谢。
答案 0 :(得分:0)
仍然不确定如何测试哪一个不起作用,但我确实找到了解决方案。 我实施了2个更改,其中之一可能起到了作用:
我添加了
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
打包到WebConfig类,然后我更改了
<script src="allstar.js" defer></script>
到
<script src="allstar.js" crossorigin="anonymous" defer></script>
现在我CORS终于不再是问题了。所有这些都是基于之前提出的Stackoverflow问题,但是代码包含大约20个独立的答案代码,因此问题就没那么多了。