GAS가 OPTIONS 요청을 처리하지 못해 발생하는 405·헤더 오류의 구조를 설명하고, 요청 방식 전환만으로 오류를 우회해 개발 안정성을 높이는 방법을 제공합니다.
Google Apps Script(GAS) 환경에서 발생하는 고질적인 GAS CORS 오류 문제를 해결하고 외부 웹사이트와 안정적인 통신을 구현하는 가장 확실한 방법입니다. Simple Request 전략을 활용하여 GAS 환경에서 발생하는 CORS 오류를 완벽히 우회하고, 클라이언트와 서버 코드를 최적화하는 구체적인 팁을 알아봅니다.
CORS 오류의 근본 원인과 HTTP 요청 방식 분석
CORS 오류는 브라우저가 보안을 위해 다른 도메인의 서버로 요청을 막을 때 발생하는 보안 정책 위반 오류입니다. 브라우저는 기본적으로 “다른 사이트(B) 서버로 데이터를 보내거나 가져오려고 하면”, 해당 서버가 정확한 허용 설정을 해주지 않으면 요청을 차단합니다.

Simple Request 전략으로 CORS 오류 우회
CORS 오류는 대부분 프리플라이트(Preflight)에서 발생합니다. Simple Request 방식으로 요청하면 이 Preflight 자체가 발생하지 않게 되어 CORS 오류를 우회할 수 있습니다.
두 가지 핵심 GAS CORS 오류는 모두 헤더 조작 문제에서 비롯됩니다. 해결책은 브라우저가 Pre-flight 요청을 보내지 않도록 하는 Simple Request 방법을 사용하는 것입니다.
Simple Request 조건
다음 조건을 만족하면 GAS는 요청을 Form Data로 인식하고, 자동으로 CORS 허용 헤더를 응답에 붙여주어 GAS CORS 오류가 발생하지 않습니다.
| 항목 | 필수 값 | 역할 |
|---|---|---|
| Method | POST (또는 GET/HEAD) | 직진 통과 |
| Content-Type | application/x-www-form-urlencoded | 정해진 서류 양식 |
Simple Request가 되기 위한 3가지 필수 조건
조건 1. 허용된 HTTP 메서드만 사용해야 함
- GET, HEAD, POST만 허용됩니다.
- PUT, PATCH, DELETE 사용 시 Simple Request는 불가하며 Preflight가 발생합니다.
조건 2. 요청 헤더는 안전한 헤더만 사용해야 함
브라우저가 허용한 기본 헤더들만 사용해야 합니다.
- Accept
- Accept-Language
- Content-Type (특정 값만)
조건 3. Content-Type은 아래 3개만 가능
아래 3개 외 다른 값이면 100% Preflight 발생합니다.
text/plain, application/x-www-form-urlencoded, multipart/form-data
❌ application/json과 같은 형식은 Simple Request가 될 수 없으며 Preflight를 유발합니다.
클라이언트와 서버 코드 최적화 가이드
Simple Request 전략을 구현하기 위해 클라이언트와 서버 코드를 다음과 같이 수정해야 GAS CORS 오류를 근본적으로 해결할 수 있습니다.
| 구분 | 기존 (CORS 발생) | 수정 (Simple Request) | 효과 |
|---|---|---|---|
| 클라이언트 헤더 | Content-Type: application/json | Content-Type: application/x-www-form-urlencoded | Pre-flight 요청 생략 |
| 서버 데이터 읽기 | `JSON.parse(e.postData.contents)` | `e.parameter.prompt` | Form Data를 바로 읽어 오류 제거 |
1. 클라이언트 (HTML/JS) 코드 예시
데이터를 `URLSearchParams`를 사용하여 Form Data 형태로 인코딩합니다.
async function callAppsScript(prompt) {
const formData = new URLSearchParams();
formData.append('prompt', prompt);
const response = await fetch(GOOGLE_SCRIPT_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded', // Simple Request 필수
},
body: formData.toString() // Form Data 전송
});
return await response.text();
}
2. 서버 (Apps Script) 코드 예시
전송된 Form Data를 `e.parameter` 객체를 통해 바로 접근합니다.
function doPost(e) {
const userPrompt = e.parameter.prompt; // e.parameter로 Form Data 직접 접근
if (!userPrompt) {
return createTextResponse("Error: 요청 본문에 'prompt'가 없습니다.");
}
return createTextResponse("성공적으로 처리되었습니다!");
}
function createTextResponse(content) {
const output = ContentService.createTextOutput(content);
output.setMimeType(ContentService.MimeType.TEXT);
return output; // setHeader 없이도 GAS가 자동 CORS 처리
}
FAQ: GAS CORS 오류 관련 자주 묻는 질문
Q1: 왜 ContentService.createTextOutput에는 setHeader가 없나요?
A1: Apps Script의 ContentService는 단순 텍스트 출력을 위해 설계되어 헤더 조작이 제한됩니다. Simple Request 전략으로 우회하는 것이 최적입니다.
Q2: Simple Request 전략이 모든 CORS 문제를 해결하나요?
A2: 대부분의 단순 POST 요청에서 발생하는 405 오류와 `setHeader` 부재 문제를 해결합니다. 특수 인증 헤더가 필요하거나 복잡한 요청의 경우, 프록시 서버 등 추가 대응이 필요할 수 있습니다.
Q3: e.parameter 대신 e.postData.contents를 써도 되나요?
A3: `e.postData.contents`는 주로 JSON 사용 시 사용되며, 이때 브라우저가 OPTIONS 요청을 보내 GAS CORS 오류가 발생할 수 있습니다. Form Data와 `e.parameter` 사용을 권장합니다.
5. 최종 GAS CORS 오류 해결 체크리스트
정리하면, GAS CORS 오류를 피하는 핵심 5가지 조건입니다.
- 클라이언트: `Content-Type`을 `application/x-www-form-urlencoded`로 설정
- 클라이언트: `URLSearchParams`로 데이터를 인코딩하여 POST
- 서버: `e.parameter`로 데이터를 읽기
- 서버: `ContentService.createTextOutput`만 사용하여 응답 반환
- 배포: Apps Script를 새 버전으로 재배포
이 간단한 Simple Request 방법으로 외부 웹사이트와 안정적인 API 통신이 가능하며, 개발 생산성과 안정성이 크게 향상됩니다. 반복되는 GAS CORS 오류를 근본적으로 해결하고 안전한 통신을 구현하시기 바랍니다.