繁体   English   中英

如何使用 angular 11 在 spring 引导中纠正与 Cors 原点相关的问题?

[英]How to correct a problem related to the Cors Origin in spring boot with angular 11?

我在 Spring 启动和 Angular 中开发的 API 有问题。 当我尝试用图像录制新的表演时,我总是有与 Cors 跨源标题相关联的相同错误。

这是我的 controller 和用于创建 Prestation 的方法

@RestController
@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
@RequestMapping("/prestations")
public class PrestationController {

    private byte[] bytes;
    @Autowired
    IPrestationService prestationService;
    @Autowired
    PrestationRepository prestationRepository;
    @Autowired
    ServletContext context;


@PostMapping
    public ResponseEntity<MessageResponse> savePrestaWithImage(@RequestParam("file") MultipartFile file, @RequestParam("prestation")String prestation)
    throws JsonParseException, JsonMappingException, Exception {
        Prestation presta = new ObjectMapper().readValue(prestation, Prestation.class);
        boolean isExist = new File(context.getRealPath("/Images/")).exists();
        if(!isExist){
            new File(context.getRealPath("/Images/")).mkdir();
            System.out.println("dossier créer");
        }
        String filename = file.getOriginalFilename(); // je recupere le nom de l'image
        String newFileName = FilenameUtils.getBaseName(filename)+"."+FilenameUtils.getExtension(filename);
        File serverFile = new File(context.getRealPath("/Images/"+File.separator+newFileName));
        try {
            System.out.println("Image");
            FileUtils.writeByteArrayToFile(serverFile, file.getBytes());
        }catch (Exception e){
            e.printStackTrace();
        }
        presta.setPhoto(newFileName);
        Prestation prestation1 = prestationRepository.save(presta);
        if(prestation1 != null){
            return new ResponseEntity<MessageResponse>(new MessageResponse(""), HttpStatus.OK);
        }else {
            return  new ResponseEntity<MessageResponse>(new MessageResponse("Prestation not saved"), HttpStatus.BAD_REQUEST);
        }

    }

这是我的 angular 服务

savePrestation(prestation: Prestation): Observable<Prestation> {
    const httpOptions = {
      headers: new HttpHeaders({
        'Content-type ': 'application/json',
        'Acces-Control-Allow-Origin': '/*'
      })
    }
    return this.http.post<Prestation>(this.SAVE_PRESTA, prestation, httpOptions).pipe(
      tap(_ => this.log(`save prestation with id = ${prestation.id}`)),
      catchError(this.handleError<any>('addPresta'))
    );
  }

这是我的 angular 方法 savePresta

savePresta() {
    const uploadData = new FormData();
    uploadData.append('imageFile', this.selectedFile, this.selectedFile.name);
    this.selectedFile.imageName = this.selectedFile.name;

    this.http.post(this.SAVE_PRESTA + '/upload', uploadData, { observe: 'response' }).subscribe(
      (response) => {
        if (response.status == 200) {
          this.service.savePrestation(this.prestation).subscribe(
            (prestation) => {
              this.prestation = prestation;
              this.goBack();
            });
          console.log('image uploaded successfull');
        } else {
          console.log('image not uploaded sucessfull')
        }
      });
  }

我仍然有同样的错误

Access to XMLHttpRequest at 'http://localhost:8080/prestations' from origin 'http://localhost:4200' 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.
POST http://localhost:8080/prestations net::ERR_FAILED

ERROR HttpErrorResponse headers: HttpHeaders status: 0 statusText: "Unknown Error" url:"http://localhost:8080/prestations", ok: false …

help me please that days that I block the top I tried everything but nothing helped

这是一个 CORS 问题,与安全问题有关。

问题

假设您的前端托管在xxx.com上,而后端托管在yyy.com上。

从浏览器的角度来看,您连接到xxx.com但向yyy.com发出请求,这很奇怪。 如果yyy.com没有明确授权从xxx.com发送请求,浏览器将阻止该请求。

现在,浏览器如何知道yyy.com授权来自xxx.com的请求? 有飞行前的请求。 浏览器执行飞行前请求并期望在响应中找到一些与 CORS 相关的 HTTP 标头。 看? 这是错误消息中所写的内容: Response to preflight request doesn't pass access control check

以下是此类 HTTP 标头的示例:

Access-Control-Allow-Origin: http://toto.example
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400

在这里, localhost:4200localhost:8080被认为是 2 个不同的来源

你能做什么?

您有 2 个解决方案:创建代理或设置正确的 HTTP 标头

创建代理

假设您在zzz.com上创建代理。 您的浏览器已连接到zzz.com ,并且所有后端调用都对zzz.com 从您的浏览器的角度来看,没有更多的跨源资源共享。

但是, zzz.com必须将前端请求重定向到xxx.com并将后端请求重定向到yyy.com 如果您决定所有后端请求都以/api之类的内容开头,则可以轻松完成此操作。 这将允许您编写一个简单的正则表达式:

  • /api => 后端开头
  • 其他 => 前端

幸运的是,在开发环境中,Angular 为此提供了内置解决方案。 您可以查看Proxying to a backend server它仅包括启动 angular 应用程序,并使用--proxy-config选项指向一个文件,例如:

{
  "/api": {
    "target": "http://localhost:8080",
    "secure": false
  }
}

(在这里,我们假设您所有的后端端点都以/api开头)

HTTP 接头

此答案提供了一些 Angular conf 的解决方案: How to resolve the CORS issue using proxy in angular

永远不要使用Access-Control-Allow-Origin: *

如果您想轻松修改 HTTP Headers 以进行测试,您可以安装 Chrome 扩展modHeader

注意:当您将 go 投入生产时,您将遇到这个问题,因此解决方案的选择必须由您在生产中所需的解决方案驱动。

在处理 cors 时,我使用非常简单的解决方案来开发 Spring Web 服务:

  1. 在SpringSecurityConfig中调用cors()方法配置cors。 因为 Spring 安全进程请求在到达 Controller 之前:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        // other configs ...
        http.cors();
        // other configs ...
  1. 在每个 controller 我使用注释 @CrossOrigin
@CrossOrigin
@RestController
public class EventController extends BaseController {
}

但是,如果将 @CrossOrigin 移动到 BaseController 可以工作,也许可以简化(我没有检查过)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM