CORS는 웹서비스를 개발하다가 항상 고민하는 문제입니다. Vue 학습 용도의 간단한 프로젝트를 진행하다가 역시 또 문제가 발생하였습니다. AWS, Azure 등의 좋은 서비스에서 제공하는 Severless를 사용하는 것이 아니라 Non-server(^^;)인 경우에도 CORS 문제를 어떻게 해결할 수 있을까를 고민하였는데 Proxy 혹은 CORS를 우회하는 라우터 서버가 있으면 좋겠다는 생각하였습니다.

그래서 Go 프로그래밍 언어도 공부할 겸 Go를 이용한 CORS 라우터 개발을 해보았습니다. 워낙 간결하고 짧게 구현이 되어 매우 놀라고 생산성이 좋다는 생각이 들었습니다.

bycors (Bypass CORS Router)

bycors는 Bypass CORS 라는 의미의 CORS 라우터 프로젝트명입니다. 그리고 이번 프로덕션 배포 서버로는 Heroku[참고1]를 사용하였습니다. Go로 만든 서비스를 Heroku에 올리는 방법은 [참고2] https://devcenter.heroku.com/articles/getting-started-with-go 를 기반으로 하였습니다.

기술구성

구분 선정기술
개발언어 go
개발IDE Visual Studio Code
코드베이스 https://github.com/lubang/bycors
서비스주소 https://bycors.herokuapp.com/route

bycors 서버 구현하기 (golang)

서버의 기능은 매우 간단합니다. X-API-TARGET 헤더가 있으면 해당 주소로 모든 Headers, Body를 전달하여 재호출하는 기능을 제공합니다.

  1. HTTP API 제공
  2. OPTIONS 명령으로 CORS 요청이 오면 Access-Control-Allow-Origin/Methods/Headers 응답
  3. GET/POST/PUT/DELETE 명령이 오면 해당 명령을 Bypass 후 응답을 받으면 다시 Client에게 응답

위의 기능은 main.go 파일 한 개에 모두 구현되어 있습니다. 아래의 코드는 1. HTTP API 제공, 2. OPTIONS 명령 처리에 대한 구현입니다.

// main.go 중 일부
func main() {
	port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("`$PORT` must be set")
	}

	router := httprouter.New()

	router.NotFound = http.FileServer(http.Dir("public"))
	router.OPTIONS("/route", routeAllowed)
	router.POST("/route", routeCors)
	router.GET("/route", routeCors)
	router.PUT("/route", routeCors)
	router.DELETE("/route", routeCors)

	log.Fatal(http.ListenAndServe(":"+port, router))
}

func routeAllowed(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	keys := reflect.ValueOf(r.Header).MapKeys()
	strkeys := make([]string, len(keys))
	for i := 0; i < len(keys); i++ {
		strkeys[i] = keys[i].String()
	}
	headres := strings.Join(strkeys, ",") + ", X-Naver-Client-Id,X-Naver-Client-Secret,X-TARGET-URL"

	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "*")
	w.Header().Set("Access-Control-Allow-Headers", headres)
}

위 routeAllowed 함수는 CORS 처리를 위해서 OPTIONS 명령이 전달되면 응답 헤더에 Access-Control-Allow-Origin/Methods/Headers 이 3가지 헤더의 허용을 추가해주는 일을 수행합니다. (main.go 전체코드: https://github.com/lubang/bycors/blob/master/main.go)

heroku에 배포하기

Go를 이용하여 서버는 간단하게 만들었습니다. 실제 서비스를 하기 위해 heroku에 배포를 합니다. 국내에서는 조금 느리지만 무료인데다 사용성도 너무 편리해서 간단한 개발 프로젝트 배포용으로 추천합니다.

Getting started[[참고^2]]에 따라서 heroku 로그인 후 다음과 같이 서비스를 생성하였습니다.

$ heroku login 
$ heroku create bycors
$ git push heroku master

단 3줄이면 구성 & 배포가 완료됩니다. 이렇게 쉽게 배포가 가능하다니 heroku 최고! 하지만 역시 heroku 답게 속도는 지독히 느립니다. bycors 배포에 약 4.6초가 소요되었습니다.

bycors API 사용하기

  • Address: https://bycors.herokuapp.com/route
  • Request
    • Headers
      • X-Naver-Client-Id
      • X-Naver-Client-Secret
      • X-TARGET-URL
    • Payload (form-data)
      • image: 이미지 파일
  • Response
    • Naver Clova 응답 그대로 반환

bycors 서비스 사용 화면

철저하게 Vue 프로젝트의 개발 및 시험을 위한 용도로 구현한 서비스입니다.