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

Posted

技术标签:

【中文标题】Moya/Alamofire - 具有相同键的 URL 编码参数【英文标题】:Moya/Alamofire - URL encoded params with same keys 【发布时间】:2015-08-10 02:02:20 【问题描述】:

我正在使用Moya Swift 框架构建在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
    /* ... */
)

谢谢。

【问题讨论】:

您能否指定,您的 API 是“GET”还是“POST”? @SohilR.Memon 这是 GET 请求 你能贴一些代码吗? 你能展示一下你用来测试的api吗 @SohilR.Memon 编码什么?!看,我需要做的是使用 Moya 框架发送带有具有相同键的 URL 参数的 GET 请求。将您的想法与任何网络和服务器隔离开来,以字符串的形式考虑这一点。最后我需要得到这个 URL 字符串http://some-site/request?param=v1&amp;param=v2&amp;param=v3。它与 POST 和其他东西无关,只是使用 Moya 或 Alamofire 框架使用相同参数键的普通 GET 请求。你知道如何实现吗? 【参考方案1】:

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

由于没有发布关于如何编码集合类型的规范,Alamofire 遵循将 [] 附加到数组值的键(foo[]=1&foo[]=2)的约定,并附加用方括号括起来的键用于嵌套字典值 (foo[bar]=baz)。

因此,对于这种情况,有 Custom ParameterEncoding 选项可以关闭,您可以在其中实际指定自己的实现,以实现您希望如何形成参数。

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

【讨论】:

什么时候不使用 Moya 是个好主意?有没有使用 Moya 的替代方法? 有很多库,你的名字 :) 你可以使用 Alamofire 或 NSURLSession 并创建自己的包装器,有一些与 Moya 非常相似的东西,它是来自 Thoughtbot 的 Swish。实际上网络层通常是相同的,所以你可以在这里看看它是如何工作的并创建你自己的:) @Voronv 我看了看。 Moya 或其他网络抽象层缺少的东西是 OAuth/JWT 请求方法,用于在触发下一个请求之前刷新/更新过期的身份验证令牌。比如auth token过期了,应该在下一次moya请求之前在客户端更新token...你有什么建议吗? @user805981这根本不是问题,这是Moya在这种情况下建议的github.com/Moya/Moya/blob/master/docs/Authentication.md#oauth我个人也是这样做的,我将所有需要的修改放在传递给moya提供程序的请求回调中。在我看来,网络层库不应该为你处理所有这些东西,否则它会变成不堪重负和沉重的类似 RestKit 的东西。这是用于 OAuth 处理的小型库 github.com/trivago/Heimdallr.swift 结合它们,祝你有美好的一天:) 我正在尝试按照您在问题中提供的示例,但我不断收到Cannot convert value of type 'EndpointSampleResponse' to expected argument type 'SampleResponseClosure' (aka '() -&gt; EndpointSampleResponse') GIST: gist.github.com/rlam3/5392927b462e3986fff58c15eb9f704f【参考方案2】:

Moya 是个好主意,但其实我觉得只要稍微想一想,我们不用太多代码就可以用 Swift 构建一个网络抽象层。

我们的目标是:

灵活性,能够有效地编辑或添加新端点 可读性,一目了然地了解我们的 API 的工作原理 代码安全,通过类型化参数实现我们期望 Xcode 提供的所有预编译优点(完成、验证)。 易于调试,意味着能够在 Web 请求之前和之后插入日志

这是我在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
    

【讨论】:

所以你们没有使用 Moya? 我喜欢这个主意。在我工作的当前项目中,网络层很有用。该应用程序不应直接触摸Alamofire。额外的网络层会获得更大的灵活性,但会增加更多的复杂性。【参考方案3】:

您可以使用格式简单地创建字符串并将其作为请求 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)

希望这会有所帮助!

【讨论】:

以上是关于Moya/Alamofire - 具有相同键的 URL 编码参数的主要内容,如果未能解决你的问题,请参考以下文章

Moya/Alamofire 请求变量问题

SAS/PROC-SQL 从具有唯一键的表转换为具有相同键的多行表

ObjectStateManager 中已存在具有相同键的对象。 ObjectStateManager 无法跟踪具有相同键的多个对象

ObjectStateManager 中已存在具有相同键的对象。 ObjectStateManager 无法跟踪具有相同键的多个对象

已添加具有相同键的项目

将具有相同键的 JSON 对象合并在一起