안녕하세요! 피피아노입니다 🎵
이번 포스팅에서는 제가 프로젝트를 공부하면서 많은 의문과 동시에 많은 부족함이 느껴졌던 URL에 대해서 정리를 해보려고 합니다.
서론
제가 제대로 된 프로젝트(?)의 구조는 어떻게 되어 있고 어떤 기술들을 쓰는지 궁금하기도 하고 좋은 코드들을 최대한 많이 접해보고 안 보고 코딩도 해보면서 실력을 쌓고자 최근 클론 코딩을 해보고 있는데 제가 배우는 클론 코딩에서 정말 많이 나오는 코드가 URL 관련 코드였습니다. (내부에서 파일을 관리해야 하니 당연한 것 같기도...)
그런데 강의에서는 일단 URL을 쓰라고 하고 URL을 써야 한다고 하니까 쓰긴 하지만 정작 이 URL이 내부적으로 어떻게 처리가 되고 있는지 또, 왜 이 URL을 써야 하는지 궁금증이 들고, 쓰더라도 제대로 원리를 알고 쓰면 이해도 잘 되고 해당 기술을 더 잘 쓸 수 있을 거라는 생각에 자세히 공부를 해보았습니다! (추가로 제가 구현하고 싶은 기능도 URL을 사용하기도 하고요!)
그럼 바로 본론으로 넘어가 보겠습니다.
URL이란 무엇일까?
먼저 URL이 뭔지 개념부터 짚고 넘어가야 할 것 같습니다. URL은 생각해 보면 우리 주변에서 정말 많이 쓰고 있습니다.
URL(Uniform Resource Locator)은 인터넷 상의 리소스를 식별하고 위치를 지정하는 문자열입니다. URL은 프로토콜, 도메인, 경로, 쿼리 파라미터 등 여러 구성 요소로 이루어져 있습니다.
예를 들어, https://www.example.com/path/to/resource?query=parameter 라는 URL을 보면 다음과 같은 부분으로 나눌 수 있습니다.
- 프로토콜(Scheme): https - 리소스에 접근하기 위한 프로토콜 (HTTP, HTTPS, FTP 등)
- 경로(Path): /path/to/resource - 서버 내 리소스의 위치
- 쿼리 파라미터(Query Parameters): ?query=parameter - 리소스에 전달되는 추가 데이터
- 도메인(Domain): www.example.com - 리소스가 위치한 서버의 주소
iOS에서의 URL 사용
iOS 앱에서 URL을 사용하는 주요 사례는 파일 업로드, 음성 파일 재생, API 호출 등이 있습니다. 이를 위해 URL, URLRequest, URLSession 등의 클래스를 활용합니다.
음성 파일 업로드에서의 URL
파일을 서버에 업로드할 때는 URLRequest를 사용하여 HTTP POST 요청을 생성하고, URLSession을 통해 요청을 보냅니다. 예제를 보면서 좀 더 자세히 알아보겠습니다.
import Foundation
func uploadFile(fileURL: URL, serverURL: URL) {
var request = URLRequest(url: serverURL)
request.httpMethod = "POST"
let boundary = UUID().uuidString
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let body = createBody(boundary: boundary, fileURL: fileURL)
request.httpBody = body
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Error uploading file: \(error)")
return
}
print("File uploaded successfully")
}
task.resume()
}
func createBody(boundary: String, fileURL: URL) -> Data? {
var body = Data()
let fileData = try? Data(contentsOf: fileURL)
let filename = fileURL.lastPathComponent
let mimetype = "application/octet-stream"
body.append("--\(boundary)\r\n".data(using: .utf8)!)
body.append("Content-Disposition: form-data; name=\"file\"; filename=\"\(filename)\"\r\n".data(using: .utf8)!)
body.append("Content-Type: \(mimetype)\r\n\r\n".data(using: .utf8)!)
body.append(fileData!)
body.append("\r\n".data(using: .utf8)!)
body.append("--\(boundary)--\r\n".data(using: .utf8)!)
return body
}
uploadFile(fileURL:serverURL:) 함수
URLRequest 생성
- URLRequest 객체를 만들어 업로드 요청을 구성합니다. 요청 URL은 serverURL을 사용합니다.
HTTP 메서드 설정
- httpMethod를 "POST"로 설정하여 POST 요청을 보냅니다.
Boundary 설정
- UUID().uuidString을 사용해 고유한 boundary 문자열을 생성합니다. 이는 멀티파트 폼 데이터의 각 부분을 구분하는 역할을 합니다.
- Content-Type 헤더에 boundary를 포함하여 설정합니다.
HTTP 바디 설정
- createBody(boundary:fileURL:) 함수를 호출해 멀티파트 폼 데이터 형식의 HTTP 바디를 생성합니다.
- 생성된 바디를 httpBody에 설정합니다.
URLSession을 사용한 요청 전송
- URLSession.shared.dataTask(with: request)를 사용해 비동기 네트워크 요청을 시작합니다.
- 요청이 완료되면 콜백 클로저에서 성공 또는 오류 메시지를 출력합니다.
createBody(boundary:fileURL:) 함수
이 함수는 멀티파트 폼 데이터 형식의 HTTP body를 생성합니다.
body 데이터 초기화
- Data 객체를 생성하여 body 데이터를 초기화합니다.
파일 데이터 읽기
- fileURL에서 파일 데이터를 읽어옵니다.
- fileURL.lastPathComponent를 사용해 파일 이름을 가져옵니다.
- 파일의 MIME 타입을 "application/octet-stream"으로 설정합니다.
멀티파트 폼 데이터 구성
- 바운더리를 추가하여 멀티파트 폼 데이터의 시작을 알립니다.
- Content-Disposition 헤더를 추가하여 파일 필드와 파일 이름을 설정합니다.
- Content-Type 헤더를 추가하여 파일의 MIME 타입을 설정합니다.
- 파일 데이터를 추가합니다.
- 바운더리를 추가하여 멀티파트 폼 데이터의 끝을 알립니다.
바디 데이터 반환
- 구성된 body 데이터를 반환합니다.
이렇게 구성된 바디 데이터는 HTTP 요청의 바디로 설정되어 서버로 전송됩니다. URLSession을 통해 비동기적으로 요청이 전송되고, 서버의 응답을 처리합니다.
오늘은 여기까지 :)
감사합니다.
잘못된 내용이 있거나 더 좋은 내용 피드백은 언제나 환영합니다!
궁금하신 부분은 댓글로 질문 부탁드립니다!
'Apple > Swift' 카테고리의 다른 글
[Swift] 배열의 유사도 회고 (11) | 2024.11.08 |
---|---|
[Swift] Actor 이해하기 (1/2) (27) | 2024.11.04 |
[Swift] 동시성(Concurrency) 톺아보기 (2/2) (2) | 2024.07.25 |
[Swift] 동시성(Concurrency) 톺아보기 (1/2) (0) | 2024.07.23 |
[Swift] 고차함수(Higher-order function) 이해하기 (2) | 2024.06.27 |