【问题标题】:Moya/Alamofire - URL encoded params with same keysMoya/Alamofire - 具有相同键的 URL 编码参数
【发布时间】: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 请求。你知道如何实现吗?

标签: ios swift alamofire


【解决方案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)

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-13
    • 2016-02-23
    • 1970-01-01
    相关资源
    最近更新 更多