반응형
소개
웹 개발에서 클라이언트와 서버 간의 데이터 전송 방식 중 하나인 URL 파라미터 방식에 대해 자세히 알아보겠습니다. 이 방식의 장단점, 보안 고려사항, 그리고 프론트엔드에서의 구현 방법까지 상세히 다루겠습니다.
URL 파라미터의 종류
Path Parameters
/api/users/{user_id}/posts/{post_id}
- 리소스를 식별하는 데 사용
- URL 경로의 일부로 포함
- 필수 값으로 처리됨
Query Parameters
/api/users?role=admin&status=active
- 필터링, 정렬, 페이지네이션에 사용
?
뒤에 key=value 형태로 추가- 선택적 값으로 처리됨
프론트엔드 구현
fetch API 사용
// Path Parameters 사용
const getUserDetails = async (userId) => {
try {
const response = await fetch(`/api/users/${userId}`, {
method: 'GET',
headers: {
'Accept': 'application/json',
}
});
if (!response.ok) {
throw new Error('User not found');
}
return await response.json();
} catch (error) {
console.error('Error:', error);
throw error;
}
};
// Query Parameters 사용
const searchUsers = async (searchParams) => {
const params = new URLSearchParams({
role: searchParams.role,
status: searchParams.status,
page: searchParams.page
});
try {
const response = await fetch(`/api/users?${params.toString()}`);
return await response.json();
} catch (error) {
console.error('Error:', error);
throw error;
}
};
Axios 사용
import axios from 'axios';
// Path Parameters
const getUserPosts = async (userId, postId) => {
try {
const response = await axios.get(`/api/users/${userId}/posts/${postId}`);
return response.data;
} catch (error) {
if (error.response.status === 404) {
throw new Error('Post not found');
}
throw error;
}
};
// Query Parameters
const searchProducts = async (searchCriteria) => {
try {
const response = await axios.get('/api/products', {
params: {
category: searchCriteria.category,
minPrice: searchCriteria.minPrice,
maxPrice: searchCriteria.maxPrice,
sort: searchCriteria.sort
}
});
return response.data;
} catch (error) {
console.error('Error:', error);
throw error;
}
};
URL 파라미터 사용의 장점
장점 | 설명 |
---|---|
캐시 가능성 | GET 요청은 브라우저에서 자동으로 캐시됨 |
공유 용이성 | URL을 복사하여 쉽게 공유 가능 |
북마크 가능 | 사용자가 특정 상태를 북마크할 수 있음 |
SEO 친화적 | 검색 엔진이 URL을 이해하고 인덱싱하기 쉬움 |
구현 간단 | 서버와 클라이언트 모두에서 처리가 간단 |
URL 파라미터 사용의 단점
단점 | 설명 |
---|---|
데이터 노출 | URL에 모든 파라미터가 노출됨 |
길이 제한 | 브라우저와 서버의 URL 길이 제한 존재 |
보안 취약성 | 중요 정보가 노출될 수 있음 |
복잡한 데이터 처리 어려움 | 복잡한 객체나 배열 전송이 제한적 |
보안 고려사항
입력 검증
// 프론트엔드 검증
const validateUserId = (userId) => {
// 숫자만 허용
const pattern = /^\d+$/;
if (!pattern.test(userId)) {
throw new Error('Invalid user ID format');
}
return userId;
};
// URL 이스케이프 처리
const safeParam = encodeURIComponent(userInput);
민감 정보 처리
- 개인식별정보(PII) URL에 포함하지 않기
- 세션/인증 토큰은 헤더로 전송
- 중요 파라미터는 POST 요청으로 전환
Rate Limiting
// 프론트엔드 요청 제한
class RequestLimiter {
constructor(limitPerMinute) {
this.requests = [];
this.limitPerMinute = limitPerMinute;
}
canMakeRequest() {
const now = Date.now();
this.requests = this.requests.filter(time => now - time < 60000);
return this.requests.length < this.limitPerMinute;
}
addRequest() {
this.requests.push(Date.now());
}
}
모범 사례
1. URL 설계
// 좋은 예시
/api/users/{userId}/posts/{postId}
/api/products?category=electronics&sort=price
// 나쁜 예시
/api/getUser?id=123
/api/doSomething?action=delete&id=456
2. 에러 처리
const fetchData = async (url) => {
try {
const response = await fetch(url);
if (response.status === 404) {
throw new Error('Resource not found');
}
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
// 에러 로깅
console.error('Fetch error:', error);
// 사용자 친화적 에러 메시지
throw new Error('Failed to fetch data. Please try again later.');
}
};
3. 캐싱 전략
const fetchWithCache = async (url) => {
const cache = await caches.open('my-cache');
const cachedResponse = await cache.match(url);
if (cachedResponse) {
return cachedResponse.json();
}
const response = await fetch(url);
cache.put(url, response.clone());
return response.json();
};
마치며
URL 파라미터를 통한 데이터 전송은 간단하고 직관적이지만, 보안과 데이터 제한 등을 고려해야 합니다. 적절한 유효성 검사와 보안 조치를 통해 안전하게 구현하는 것이 중요합니다.
'파이썬' 카테고리의 다른 글
파이썬 개발을 위한 VSCode 셋팅 가이드 (2) | 2025.01.03 |
---|---|
데이터 클래스 비교: dataclass vs Pydantic BaseModel (0) | 2024.12.08 |
[Python 프로파일링] py-spy와 yappi로 파이썬 코드 성능 분석하기 (0) | 2024.12.02 |
SQLAlchemy: 데이터베이스 툴킷 (3) | 2024.11.13 |
ChatGPT API의 function_call (1) | 2024.02.11 |