iOS

[Swift] Alamofire url Parameter 한글 인코딩

램램 2023. 1. 20. 07:05
AF.request(url+"?stationName=\(encodedName)", // url에 해당 query 만 붙여주고 나머지는 그대로 params 로 전달
                   method: .get,
                   parameters: params)
        .responseDecodable(of: AirPollutionRSP.self){
        ...
        }

Alamofire URL 인코딩하기

미세먼지 앱을 만들면서 에어코리아 의 오픈 API 를 사용하려 했는데 (늘 그렇듯이) 이슈가 발생했다.

<errMsg>SERVICE ERROR</errMsg>
<returnAuthMsg>SERVICE_KEY_IS_NOT_REGISTERED_ERROR</returnAuthMsg>
<returnReasonCode>30</returnReasonCode>

이런 에러메세지가 떠서 처음엔 서비스 키를 잘못 입력했나 했지만

Postman을 이용해서 request를 확인해보면 정상적으로 응답을 받아오는 것을 볼 수 있었다..

몇 번의 삽질과 검색으로 얻어낸 결론은 한글과 특수문자 인코딩이 문제였다는 것이다.

에어코리아의 API의 명세를 보면 측정소 이름을 "종로구" 와 같이 한글로 입력받는데 Swift 에서 유니코드인 한글을 url로 제대로 보내지 못하기 때문이다.

(+ 삽질하면서 깨달은 건데 주소창이나 postman을 이용할 때는 인코딩 된 키를 사용해야 하고 Swift에서는 디코딩 된 키를 parameter로 넣어야 한다..! )

addingPercentEncoding

간단한 해결방법은 swift의 addingPercentEncoding으로 올바르게 인코딩된 string 값을 url로 이용하는 것이다.

AF.request("MyUrl".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")
            .responseDecodable(of: "MyResponseModel") { response in
                guard case .success(let data) = response.result else {return}
                print(data)
            }
            .resume()

이렇게 해결할 수 있지만 현재 보내는 url request에 많은 parameter들이 포함되어있어 parameter를 그대로 사용하면서 인코딩 하고 싶었다.

한글 Parameter

한글 인코딩은 영어 검색..이 잘 안돼서 그냥 위의 방법을 조금 응용해서 사용했다.

url을 통째로 인코딩하는 대신 별도의 함수를 만들어서 parameter에 값을 넣을 때 한번 함수를 거쳐서 넣었다.

func encodeString(_ string: String) -> String{
        return string.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
    }

퍼센트 인코딩 값을 print 해보면 잘 나온다.

실제로 이 값을 주소창이나 postman에 한글이 들어가는 stationName 자리에 한글 대신 이 함수를 통해 얻은 퍼센트 인코딩 값을 넣어보면 잘 나온다.

stationName 에 이전의 '성북구' 대신 퍼센트 인코딩된 값이 들어가도 잘 나옴

그래서 이 값을 바로 아래와 같이 활용하려 하였으나..

let params : Parameters = [
            "stationName" : encodeString({관측소이름}), // 이렇게 하지마세요..
            "dataTerm" : "DAILY",
            "pageNo" : "1",
            "numOfRows" : "2",
            "returnType" : "json",
            "serviceKey" : "{디코딩된 키}"
        ]

이렇게 넣으면 Swift 에서 이 값을 한 번 더 퍼센트 인코딩하기 때문에 %EC 를 %25EC로 바꿔서 전달한다. (% 문자의 퍼센트 인코딩 값이 %25이기 때문에)

 

이 글을 참고해서 방법을 찾았다.

https://stackoverflow.com/questions/42010219/how-to-block-alamofire-from-encoding-of-url-parameters

 

How to block Alamofire from encoding of URL parameters

I have an url like that https://www.mysite/v1/search?N=4249847587+1798040122 I use Alamofire like that Almofire.request(.GET, "https://www.mysite/v1/search", parameters: ["N","4249847587+17980...

stackoverflow.com

1. Custom Encoding 클래스를 만들어서 인자로 넘겨주기

2. 아예 url에 붙여서 넘겨주기

정도로 해결할 수 있을 것 같았는데 1번은 너무 코드가 길어질 것 같아서 좀 야매같지만 훨씬 간단한 2번 방법으로 해결했다

AF.request(url+"?stationName=\(encodeString({한글스트링}))",
                   method: .get,
                   parameters: params)
        .responseDecodable(of: AirPollutionRSP.self){

한글 인자만 url에 붙여주고 나머지 인자들은 여전히 params 에 넣어서 전달했더니 됐다..!

🥹

 

 

추가 - Alamofire request 프린트 하기

이 이슈를 해결하면서 어디가 문제인지 좀 뜯어보고 싶어서 alamofire에서 보내는 request를 콘솔에 찍어보고 싶었다. Alamofire에 자체 내장된 request 프린트 함수는 없는 것 같아서 검색해보니 스택오버플로에서 이런 코드를 찾을 수 있었다.

extension Request {
    public func debugLog() -> Self {
        #if DEBUG
            debugPrint("=======================================")
            debugPrint(self)
            debugPrint("=======================================")
        #endif
        return self
    }
}

익스텐션의 형태의 코드 스니펫이기 때문에 간단하게 alamofire 를 사용할 파일 마지막에 이 코드를 추가한 후 request 를 보내는 부분에 .debugLog() 를 추가하기만 하면 된다.

이렇게!

AF.request(url).debugLog().responseDecodable(of: AirPollutionRSP.self){
...
}

 

+)

혹시 더 좋은 방법이 있다면 알려주세요..!