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 자리에 한글 대신 이 함수를 통해 얻은 퍼센트 인코딩 값을 넣어보면 잘 나온다.
그래서 이 값을 바로 아래와 같이 활용하려 하였으나..
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){
...
}
+)
혹시 더 좋은 방법이 있다면 알려주세요..!
'iOS' 카테고리의 다른 글
[Swift] 코드로 TabBar 커스텀 아이콘 적용하기 (0) | 2023.01.31 |
---|---|
[Swift] Custom Navigation Bar 만들기 (0) | 2023.01.29 |