자꾸 cors 오류가 뜨는데, 그 이유를 모르겠습니다.

자꾸 cors 오류가 뜨는데, 그 이유를 모르겠습니다.

작성일 2024.01.02댓글 1건
    게시물 수정 , 삭제는 로그인 필요

프론트엔드는 리엑트, 백엔드는 스프링부트로 개발을 하고 있습니다.

회원가입 부분에서 아이디와 비밀번호를 적고, 회원가입 버튼을 누르려고 할 때, 오류가 납니다.

오류의 종류는 

Access to XMLHttpRequest at 'http://localhost:8080/register' from origin 'http://localhost:3000' 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.

입니다.

(데이터베이스는 postgresql을 쓰고 있습니다.)

다음은 코드입니다.

리엑트(회원가입 부분)

// RegisterPage.js
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
//import axios from 'axios';
const RegisterPage = () => {
    /*
    axios를 사용해서 서버로 post 요청을 보내고, 사용자가 입력한 아이디와 비밀번호를 전송한다.
    1.react 컴포넌트 생성
    const RegisterPage = () => { ... }에서 RegisterPage는 함수형 컴포넌트를 정의한다.
    이 컴포넌트는 회원가입 페이지를 나타낸다.

    2.useState를 사용한 상태 관리
    const [username, setUsername] = useState('');
    와 const [password, setPassword] = useState('');는 React의 useState 훅을 사용하여 각각 아이디와 비밀번호의 상태를 관리한다.

    3.폼 제출 핸들러 함수
    const handleSubmit = async (e) => { ... }는 폼 제출을 처리하는 함수이다.
    async 함수로 비동기 처리를 수행하며,
    e.preventDefault()를 호출하여 기본 제출 동작을 막는다.

    4.axios를 사용한 서버 통신

    axios.post('http://localhost:8080/register', { username, password });
    는 axios를 사용하여 서버에 POST 요청을 보낸다.
     'http://localhost:8080/register'는 Spring Boot에서 정의한 회원가입을 처리하는 엔드포인트이다.
   
     5.컴포넌트 내용 반환

     return ( ... )에서는 JSX를 사용하여 실제로 화면에 표시되는 컴포넌트의 구조를 정의한다.
     <form> 요소 안에 아이디와 비밀번호 입력 필드, 회원가입 버튼, 돌아가기 버튼이 있다.

    6.이벤트 핸들러 함수와 상태 업데이트:

입력 필드에는 onChange 이벤트에 연결된 함수를 통해 입력 값을 상태에 업데이트한다.
예를 들어, onChange={(e) => setUsername(e.target.value)}는 아이디 입력 필드 값이 변경될 때마다 setUsername 함수를 호출하여 상태를 업데이트한다.

    7.React Router의 Link 컴포넌트 활용:

    <button><Link to="/">돌아가기</Link></button>에서는
    React Router의 Link 컴포넌트를 사용하여 홈 페이지로 이동하는 링크를 만든다.
    */

   

    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');

    const handleSubmit = async (e) => {
        e.preventDefault();

        try {
           

            // 'api/register'만 적어야 세션과 쿠키가 넘어온다. proxy의 도메인이 cors를 해결해 주기 때문이다.
            //api는 setupProxy 파일에서 구현한 부분이다.
            const response = await axios.post('http://localhost:8080/register', { username, password });
            console.log(response.data); // Optional: Log server response
        } catch (error) {
            if (error.response) {
                // 서버가 응답한 상태 코드가 2xx가 아닌 경우
                console.error('Server responded with an error:', error.response.data);
            } else if (error.request) {
                // 요청이 전송되었지만 응답이 없는 경우
                console.error('No response received:', error.request);
            } else {
                // 오류를 발생시킨 요청을 설정하는 중에 문제가 발생한 경우
                console.error('Error setting up the request:', error.message);
            }
        }
    };

    return (
        <div>
            <form onSubmit={handleSubmit}>
                아이디:{' '} <input type="text" name="username" value={username} onChange={(e) => setUsername(e.target.value)} /><br />
                비밀번호: {' '}<input type="password" name="password" value={password} onChange={(e) => setPassword(e.target.value)} /><br />
                <input type="submit" value="회원가입" />
                <button><Link to="/">돌아가기</Link></button>
            </form>
        </div>
    );
};

export default RegisterPage;

백엔드

WebConfig.java

package com.example.demo;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;



/*
 * 기본적으로 브라우저는 다른 출저에서 리소스를 로드하는 것을 막는다.
 * 따라서 react 앱이 실행 중인 출저에서 스프링부트 서버의 출저로의 요청이 차단 될 수 있다.
 * 그래서 springboot 어플에서 cors를 허용하는 설정을 추가해야 한다.
 * */

@Configuration
public class WebConfig implements WebMvcConfigurer{
//cors를 백엔드에서 허용할 수 있도록 한다.
@Override
    public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/register")
        .allowedOrigins("http://localhost:3000")
        .allowCredentials(true)
        .allowedMethods("GET", "POST", "PUT", "DELETE")
        .allowedHeaders("*");
        
        /*
         * .exposedHeaders("Access-Control-Allow-Origin")를 추가하여 
         * 브라우저가 요청에 대한 응답을 허용하는 데 필요한 헤더를 알 수 있게 합니다.
         * */

}
}

MyController.java

package com.example.demo;




import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import lombok.RequiredArgsConstructor;


//cors 설정을 직접 추가한다.

@Controller
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
@RequiredArgsConstructor
public class MyController {
@Autowired //autowired를 통해 쉽게 객체를 불러온다.
private  NeuralNetworkRepository neuralnetworkrepository;
private  MemberService memberService;
//기본 페이지를 요청한다.
@GetMapping("/")
public String test() {
return "MainPage"; //Mainpage를 찾아간다.(우리는 리엑트와 연동했으므로 리엑트 파일을 찾아간다.)
}
@GetMapping("/login")
public String loginPage() {
return "LoginPage";
}
//회원가입 페이지를 요청한다.
@GetMapping("/register")
public String registerPage() {
return "RegisterPage";
}
@PostMapping("/register")
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
//클라이언트에서 json 형식으로 데이터를 전송하고 있으므로, requestbody를 사용해야 한다.
    public String save(@RequestBody Map<String, String> requestBody,
                       RedirectAttributes redirectAttributes) {
        // Use memberService to handle registration
String username = requestBody.get("username");
    String password = requestBody.get("password");
try {
            // 중복된 아이디 확인
            if (neuralnetworkrepository.existsByUsername(username)) {
                redirectAttributes.addFlashAttribute("error", "이미 사용 중인 아이디입니다. 다른 아이디를 선택해주세요.");
                return "redirect:/register";
            }

            // 아이디가 중복되지 않은 경우 저장
            memberService.addNeuralNetwork(username, password);

            // 회원가입이 성공한 경우 리다이렉션하면서 성공 메시지 전달
            redirectAttributes.addFlashAttribute("success", "User registered successfully!");
            return "redirect:/";
        } catch (Exception e) {
            // 예외 처리
            redirectAttributes.addFlashAttribute("error", "회원가입 중 오류가 발생했습니다.");
            return "redirect:/register";
        }
    }

    @GetMapping("/result")
    public String resultPage() {
        return "ResultPage";
    }
}

SecurityConfig.java
package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

//SpringSecurity를 이용해서 보안 설정을 구현한 클라스이다.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfiguration  {

private final MemberService userDetailsService;

    public SecurityConfig(MemberService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    //http 보안 설정을 정의한다.
    //register는 모든 사용자들에게, 그 외 요청은 인증된 사용자들에게만.
    
protected void configure(HttpSecurity http) throws Exception {
http
         .cors() // CORS 설정을 허용
             .and()
         
             .authorizeRequests()
             .requestMatchers("/public/**").permitAll() // 특정 경로에 대한 권한 없이 허용
             .anyRequest().authenticated() // 나머지 요청은 인증 필요
             .and()
         .formLogin()
             .loginProcessingUrl("/login") // 로그인 처리 URL
             .usernameParameter("username")
             .passwordParameter("password")
             .permitAll()
             .and()
         .logout()
             .logoutUrl("/logout") // 로그아웃 처리 URL
             .permitAll()
             .and()
         .httpBasic(); // 기본 HTTP 기반 인증 사용
       
    }
    @Bean
    //bean의 이름을 변경하여 충돌을 피한다.
    //비밀번호 암호화를 위한 메서드이다.
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

Person.java

package com.example.demo;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;


//사용자 정보를 저장할 엔터티 클래스이다.

@Data
@Entity
@Table(name ="person")
public class Person {
@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String username;
private String password;
public Person() {
}
public Person(String username, String password) {
        this.username = username;
        this.password = password;
    }
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}

//GeneratedValue(strategy = GenerationType.IDENTITY)는 데이터베이스가 자동으로 아이디를 생성,할당하도록 한다.
//alt+shift+s에서 getter/setter를 만드는 옵션으로 getter,setter를 쉽게 생성한다.
}



추가내공 100 있습니다. 감사합니다.



profile_image 익명 작성일 -

CORS 오류는 서버와 클라이언트 간의 보안 정책으로 인해 발생하는 문제입니다. 오류 메시지를 보면, 클라이언트(리액트 앱)에서 서버(스프링 부트)로의 요청이 차단되었다는 것을 나타냅니다. 이 문제를 해결하려면 CORS (Cross-Origin Resource Sharing) 설정을 올바르게 구성해야 합니다.

클라이언트에서 서버로의 요청이 막히는 문제를 해결하기 위해 스프링 부트에서 CORS를 허용하는 방법을 제공하는데, 아래와 같이 설정해보세요.

1. **스프링 부트 백엔드 설정:**

WebConfig.java 파일에서 CORS 설정을 다음과 같이 변경해보세요.

```java

@Configuration

public class WebConfig implements WebMvcConfigurer {

@Override

public void addCorsMappings(CorsRegistry registry) {

registry.addMapping("/**")

.allowedOrigins("http://localhost:3000") // 클라이언트 주소

.allowedMethods("GET", "POST", "PUT", "DELETE") // 요청 허용 메소드

.allowCredentials(true); // 자격 증명 허용

}

}

```

2. **보안 설정 변경:**

SecurityConfig.java 파일에서 configure 메서드에 요청 경로를 추가해보세요.

```java

protected void configure(HttpSecurity http) throws Exception {

http.cors().and()

// ... 이전 설정 ...

.authorizeRequests()

.antMatchers("/register").permitAll() // CORS 허용 경로

// ... 이후 설정 ...

}

```

위 설정을 통해 CORS 문제를 해결할 수 있을 것입니다. 하지만 이 설정은 보안 상의 이유로 모든 경로에 대해 허용하는 것이 아니라 필요한 부분에 대해서만 허용하도록 설정하였습니다. 원하는 경로와 요청에 맞게 설정을 변경하시면 됩니다.

github 오류가 자꾸 뜨는데 이유가...

... 오면 자꾸 에러가 뜨는데 .git 폴더를 다시 지우고 깔아도 계속 같은 오류가 뜨는데 왜그러는걸까요?... 계속 뜨는데 이유가 뭘까요 ?ㅠㅠ 질문자분의 현재...

자꾸 오류떠서 질문해요..

폴더 data에 sample_text.txt라는 파일 만들었는데 자꾸 오류가뜨는데 이유가... txt 이렇게 하지마시고 루트 디렉토리까지 복사해서 입력해보세요.

컴활1급 엑셀 매크로 오류나는 이유

자꾸 다음 오류 메세지가 뜨는데 어디가 잘못된 건가요? 제가 쓴 식 입니다 [>=1000]... 정말 모르겠습니다 도와주세요 다음과 같이 수정해주세요. 조건은 2개까지만...

라고 뜨는데 그 이유를 모르겠습니다.

... 홈페이지에 접속해보면 항시 좌측하단에 [페이지에 오류가 있습니다] 또는 [작업을 마쳤으나 페이지에 오류가... 있는데 그곳 안에서 스크립트 오류가 발생 합니다. sjisbmoc

구글 결제 오류

... 찾았는데도 모르겠습니다.구글 깊카로 결제하고 싶은데 해결방법좀 알려주세요...ㅠ^ㅠ 질문 : 질문구글 결제 오류 이렇게 뜨는데 몇시간째 찾아봐도 모르겠는데 뭘...

도중에 자꾸 오류가 뜨는데 그이유가...

인터넷을 하다보면 가끔씩 오류가 뜹니다. 뜬는 내용을 보면 "이 페이지는 잠재적으로... " 이렇게 떠요 어떻게 해야하나요 오류창이 안뜨가 하는 방법좀 익스플로러 5.X 대의...

자꾸 뜨는데 이유를 모르겠습니다

... 뜹니다 이유가 무엇인지 알려주시면 진심으로 감사합니다 내공은 100점을 드리겠습니다... 웹브라우저상의충돌로 인한 오류일수 있습니다 . 만약에 프로그램문제라면...