Moya/Alamofire - URL 具有相同密钥的编码参数

Moya/Alamofire - URL encoded params with same keys

我正在使用 Moya Swift framework for networking layer which is constructed on top of Alamofire

目前,我正在尝试使用具有相同密钥的 URL 编码参数发送请求。

http://some-site/request?param=v1&param=v2&param=v3

我已经尝试像这样将这些参数分组到 Set 或 NSSet 或 Array 中,但没有任何方法可以达到预期的结果。

["param": ["v1", "v2", "v3"]];

["param": Set(arrayLiteral: "v1", "v2", "v3")]

对于 Moya 或 Alamofire 本身的任何帮助,我们将不胜感激。

编辑: 下面是一些示例代码以提供基本概念:

Api 路由器设置

import Moya

// MARK:- Enum Declaration

enum ApiRouter {
    case XAuth(login: String, password: String)
    case SomeRequest(params: [String])
}

// MARK:- Moya Path

extension ApiRouter: MoyaPath {
    var path: String {
        switch self {
        case .XAuth:
            return "/authorization"
        case .SomeRequest:
            return "/some-request"
        }
    }
}

// MARK:- Moya Target

extension ApiRouter: MoyaTarget {
    private var base: String {
        return "http://some-site"
    }
    var baseURL: NSURL {
        return NSURL(string: base)!
    }

    var parameters: [String: AnyObject] {
        switch self {
        case .XAuth(let login, let password):
            return [
                "email": login,
                "password": password
            ]
        case .SomeRequest(let params):
            return [
                "params": params
            ]
    }

    var method: Moya.Method {
        switch self {
        case .XAuth:
            return .POST
        case .SomeRequest,
            return .GET
        }
    }

    var sampleData: NSData {
        switch self {
        case .XAuth:
            return "{}".dataUsingEncoding(NSUTF8StringEncoding)
        case .ServiceRequests:
            return "{}".dataUsingEncoding(NSUTF8StringEncoding)
        }
    }
}

Api 提供商设置

    let endpointsClosure = { (target: ApiRouter) -> Endpoint<ApiRouter> in
    let endpoint = Endpoint<ApiRouter>(
        URL: target.baseURL.URLByAppendingPathComponent(target.path).absoluteString!,
        sampleResponse: EndpointSampleResponse.Success(200, { target.sampleData }),
        method: target.method,
        parameters: target.parameters,
        parameterEncoding: parameterEncoding(target)
    )
    switch target {
    case .XAuth:
        return endpoint
    default:
        let token = "some-token"
        return endpoint.endpointByAddingHTTPHeaderFields(["Authorization": "Bearer: \(token)"])
    }
}

func parameterEncoding(target: ApiRouter) -> Moya.ParameterEncoding {
    switch target {
    case .XAuth:
        return .JSON
    case .SomeRequest:
        return .URL
    }
}

let apiProvider = MoyaProvider(endpointsClosure: endpointsClosure)

apiProvider.request(ApiRouter.SomeRequest(params: ["v1", "v2", "v3"], completion: { (data, statusCode, response, error) in
    /* ... */
})

谢谢。

您可以简单地使用格式创建字符串并将其作为请求传递 URL:

http://some-site/request?param=v1&param=v2&param=v3

String url: String = String(format: "http://some-site/request?param=%@&param=%@&param=%@", v1, v2, v3)

希望对您有所帮助!

所以我找到了一个非常简单明了的解决方案。 阅读 Alamofire 的文档我发现了这个:

Since there is no published specification for how to encode collection types, Alamofire follows the convention of appending [] to the key for array values (foo[]=1&foo[]=2), and appending the key surrounded by square brackets for nested dictionary values (foo[bar]=baz).

因此,对于这种情况,有 Custom ParameterEncoding 选项,它会关闭,您可以在其中实际指定您自己的参数实现方式待组建。

Here同样的问题,同样的答案。

Moya是个好主意,但我其实觉得稍微思考一下,我们可以用Swift构建一个网络抽象层,代码不多

我们的目标是:

  • 灵活性,能够有效地编辑或添加新端点
  • 可读性,一目了然地了解我们的 API 是如何工作的
  • 代码安全,类型化参数允许我们期望从 Xcode.
  • 获得的所有预编译优点(完成、验证)
  • 易于调试,这意味着能够在网络请求前后插入日志

这是我在 dummy project 上的结果:

public class API {

public static let baseURL: String = "http://colourlovers.com/api"

public enum Endpoints {

    case Colors(String)
    case Palettes(String)
    case Patterns(String)

    public var method: Alamofire.Method {
        switch self {
        case .Colors,
             .Palettes,
             .Patterns:
            return Alamofire.Method.GET
        }
    }

    public var path: String {
        switch self {
        case .Colors:
            return baseURL+"/colors"
        case .Palettes:
            return baseURL+"/palettes"
        case .Patterns:
            return baseURL+"/patterns"
        }
    }

    public var parameters: [String : AnyObject] {
        var parameters = ["format":"json"]
        switch self {
        case .Colors(let keywords):
            parameters["keywords"] = keywords
            break
        case .Palettes(let keywords):
            parameters["keywords"] = keywords
            break
        case .Patterns(let keywords):
            parameters["keywords"] = keywords
            break
        }
        return parameters
    }
}

public static func request(
    endpoint: API.Endpoints,
    completionHandler: Response<AnyObject, NSError> -> Void)
    -> Request {

        let request =  Manager.sharedInstance.request(
            endpoint.method,
            endpoint.path,
            parameters: endpoint.parameters,
            encoding: .URL,
            headers: nil
            ).responseJSON { response in

                if (response.result.error) != nil {
                    DDLogError("\n<----\n" + response.result.error!.description)
                    completionHandler(response)
                } else {
                    DDLogInfo("\n<----\n" + response.response!.description)
                    completionHandler(response)
                }
        }
        DDLogInfo("\n---->\n" + request.description)
        return request
    }
}