발생 날짜: 2022/7/12
해결 날짜: 2022/7/12
키워드:CORS
프론트단에서 Fetch
와 Axios
api를 사용하여 로그인을 위한 POST 요청을 보냈다.
Access to XMLHttpRequest at 'http://146.56.39.196:8080/api/users/login' 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.
POST 요청을 보냈더니 브라우저 콘솔에 에러 메세지가 뜨면서 서버로부터 정상적인 응답이 오질 않았다.
CORS
정책 위반
CORS(Cross Origin Resource Sharing) 정책은 서로 다른 도메인이 네트워크 통신을 할때 브라우저에서 서버가 허용하는 Origin만 서버와 통신할 수 있도록 제한을 둔 보안 정책이다.
fetch
api를 사용하여 서버에 요청을 보내게 되면,
클라이언트는 위와 같이 예비 요청
과 본 요청
2가지 요청을 서버에 보내게 되는데 예비 요청
에는 HTTP methods
중 OPTIONS
를 사용하여 요청을 보내게 된다. 이때 서버는 예비 요청
을 받아 클라이언트의 도메인인 Origin
이 서버에서 CORS
허용을 해주고 있는 도메인인지 아닌지 확인한다. 만약 해당되지 않는다면,
preflight request doesn't pass access control check
라는 에러를 발생시킨다. preflight request
가 예비 요청
을 의미하고 있다. 즉, 이러한 에러가 떴다면 그것은 서버에서 예비 요청
을 받은 후 서버에서 허용하고 있는 도메인이 아니기 때문에 접근을 차단하겠다는 의미가 된다.
서버 측에서 응답 헤더에다가 Access-Control-Allow-Origin: *
를 설정해주면 모든 Origin이 요청을 보낼 수 있도록 허용하는 것인데 이렇게 되면 CSRF attack
의 표적이 될 수 있다고 한다. 그러므로 허용할 Origin
은 엄격히 설정해주는게 보안상 안전하다고 생각한다.
https://evan-moon.github.io/2020/05/21/about-cors/
발생 날짜: 2022/7/17
해결 날짜: 2022/7/17
키워드:Label 태그
label
태그의 파일 찾기
텍스트를 웹페이지에서 클릭하면 input type='file'
이 작동하도록 만들려고 했다.
<label for='file'>파일 찾기</label>
<input type='file' />
브라우저 콘솔창에 for
대신 htmlFor
를 사용하라는 경고가 뜨면서 코드가 의도했던대로 작동하지 않는다.
React
에서는 label
요소의 for
attribue 대신 htmlFor
를 사용하도록 되어있다.
<label htmlFor='file'>파일 찾기</label>
<input type='file' />
for
대신 htmlFor
attribute 사용
<label htmlFor='file'>파일 찾기</label>
<input type='file' />
htmlFor로 프로퍼티를 변경해줬음에도 여전히 label을 눌렀을때 input file이 트리거되지 않는다.
label
태그가 htmlFor
의 값을 통하여 input
을 작동시키려면 input
의 id
값을 사용해야하는데 id
가 없었다.
<label htmlFor='file'>파일 찾기</label>
<input type='file' id='file' />
id='file'
을 추가해줬더니 input file
이 트리거 된다.
발생 날짜: 2022/7/17
해결 날짜: 2022/8/3
키워드:input value
파일 찾기
버튼을 눌렀을 때 첨부파일
부분이 서버에 업로드할 파일명으로 바뀌어야하는데 바뀌지 않는다.
<input id='post-upload-name' value='첨부파일' placeholder='첨부파일' readOnly />
value
가 '첨부파일'
문자열로 고정된 상태.
document.querySelector('#post-upload-name').value = e.target.files[0]
value
가 '첨부파일'
문자열로 고정된 상태이기 때문에 querySelector
메서드를 사용하여 value
를 바꾸는게 불가능한 것이었다.
const [file, setFile] = useState('');
상태 file
을 생성.
<input type='file' multiple onChange={(e) => {
for (let i = 0; i < e.target.files.length; i++)
setFile(file + " " + e.target.files[i].name);
}} />
onChange
이벤트 리스너함수를 이용하여 setFile
로 file
상태 변경.
<input id='post-upload-name' value={file} placeholder='첨부파일' readOnly />
value='첨부파일'
이 아닌 value={file}
로 value
가 상태 file
이 되었으므로 file
이 업데이트되면 input value
도 업데이트 됨.
발생 날짜: 2022/7/17
해결 날짜: 2022/8/3
키워드:multipart/form-data
,input file
,FormData
서버로 이미지 파일들을 전송해야하는데 서버에서 이미지 파일들을 받지 못함.
formData
를 사용하지 않았기 때문.
formData
사용
const [imageName, setImageName] = useState([]);
function handleSubmit(e) {
e.preventDefault();
const formData = new FormData();
formData.append('imageName', imageName);
// codes...
formData
를 사용했지만 이미지 파일을 2개 이상
담은 배열을 보내면 서버측에서 에러 발생
formData
를 이용하여 이미지 파일들을 다수 보내는 방법이 잘못됨.
imageName.forEach(file => {
formData.append('imageName', file);
});
forEach
문을 사용하여 상태 변수 imageName
에 담긴 배열 요소들을 각각 따로 formData
에 추가해줌.
console.log([...formData]);
위 코드를 사용하여 formData
내부에 입력된 데이터들을 확인 가능.
formData
내부를 살펴보는데 참고한 자료
https://stackoverflow.com/a/45673708/15060678
FormData
는 폼 태그를 AJAX
통신을 사용하여 전송할때 사용할 수 있는 API.
// form이 폼 태그라고 가정하면 `FormData`에 전달하여 AJAX통신때 form태그를 보낼 수 있게 한다.
// 폼 태그는 submit 즉시 새로고침되어 ajax통신과 연동될 수 없으므로
// e.preventDefault(); 메서드를 사용하여 새로고침을 방지한 후 FormData에
// form태그를 전달하는 방식으로 전송 가능하다.
const formData = new FormData(form);
FormData
오브젝트를 AJAX
통신에 사용할 경우
axios.post(url, formData, {
headers: { 'Conetent-Type': 'multipart/form-data' }
}
Content-Type
을 headers
에 명시적으로 지정해줄 필요가 없다. 그 이유는 request body
에 추가된 formData
로 인해 자동으로 content-type
이 multipart/form-data
로 변경되기 때문이다.
그러므로, formData
를 request body
에 올릴 경우에는
axios.post(url, formData);
처럼 headers
에 content-type
을 지정하지 않아도 된다.
발생 날짜: 2022/8/6
해결 날짜: 2022/8/7
키워드:nth-of-type
협업 스터디에 새로 오신 디자이너 팀원 분이 기존의 같은 크기의 카드들로만 있었던 카드 레이아웃을 위 이미지에 나오는 레이아웃 구현이 가능한지 여쭤보셨다.
display: grid
를 써야함을 알았지만 카드들의 크기가 다 같은 것이 아닌 특정 순번의 카드는 크기가 다른 카드의 크기보다 4배 크기였다. 그리고 이 패턴이 반복되게 해야했다.
.cards__item:nth-of-type(9n + 2),
.cards__item:nth-of-type(9n + 7) {
grid-column: span 2;
grid-row: span 2;
border: 1px red solid;
height: 100%;
}
nth-of-type
속성을 써서 특정 카드에만 CSS를 적용하는 것을 생각해냈다.
grid-column
과 grid-row
속성에 span 2
값을 줘서 그리드 레이아웃에서 행렬 각 2칸씩 차지하는 카드가 되도록 했다. 디자이너 팀원 분이 의도하신 대로 특정 순번에만 큰 이미지가 오도록 순번을 연산해줄 수 있는 수식이 필요했다. 다음 큰 카드가 언제 오는지 알아본 다음 항상 같은 패턴의 큰 카드들의 사이에는 8개의 카드가 있음을 알아냈다. nth-of-type
은 n
이 0
부터 시작하므로 1번째 패턴과 2번째 패턴 카드에 각각 +2
와 +7
을 설정하여 첫번째 큰 카드들의 위치를 정해줬다. 그 뒤부터는 항상 9
번째마다 큰 카드들이 위치하게 된다.