如何在 Swift 中发出 NSURLSession POST 请求
Posted
技术标签:
【中文标题】如何在 Swift 中发出 NSURLSession POST 请求【英文标题】:How to make NSURLSession POST request in Swift 【发布时间】:2017-02-02 08:42:54 【问题描述】:嗨,我是 Swift 的初学者,我正在尝试让 NSURLSession “发布”请求发送一些参数,如我下面的代码
根据我下面的代码响应不是来自服务器,请有人帮助我
BackGroundClass:-
import UIKit
protocol sampleProtocal
func getResponse(result:NSDictionary)
func getErrorResponse(error:NSString)
class BackGroundClass: NSObject
var delegate:sampleProtocal?
func callPostService(url:String,parameters:NSDictionary)
print("url is===>\(url)")
let request = NSMutableURLRequest(URL: NSURL(string:url)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
//Note : Add the corresponding "Content-Type" and "Accept" header. In this example I had used the application/json.
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(parameters, options: [])
let task = session.dataTaskWithRequest(request) data, response, error in
guard data != nil else
print("no data found: \(error)")
return
do
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary
print("Response: \(json)")
self.mainResponse(json)
else
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)// No error thrown, but not NSDictionary
print("Error could not parse JSON: \(jsonStr)")
self.eroorResponse(jsonStr!)
catch let parseError
print(parseError)// Log the error thrown by `JSONObjectWithData`
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
self.eroorResponse(jsonStr!)
task.resume()
func mainResponse(result:NSDictionary)
delegate?.getResponse(result)
func eroorResponse(result:NSString)
delegate?.getErrorResponse(result)
视图控制器:-
import UIKit
class ViewController: UIViewController,sampleProtocal
override func viewDidLoad()
super.viewDidLoad()
let delegate = BackGroundClass();
delegate.self;
let params = ["scancode":"KK03799-008", "UserName":"admin"] as Dictionary<String, String>
let backGround=BackGroundClass();
backGround.callPostService("url", parameters: params)
func getResponse(result: NSDictionary)
print("Final response is\(result)");
func getErrorResponse(error: NSString)
print("Final Eroor code is\(error)")
【问题讨论】:
你遇到了什么错误.. 我没有收到错误,但没有收到响应,并且邮递员响应即将到来 您是否在应用中添加了传输安全性,请参阅***.com/questions/30731785/… 是的,我已经在我的 plist 文件中添加了传输安全 检查你的网址和参数是否正确发送 【参考方案1】:Swift 4 使用 json 有效负载发布示例-
func postAction(_ sender: Any)
let Url = String(format: "your url")
guard let serviceUrl = URL(string: Url) else return
let parameterDictionary = ["username" : "Test", "password" : "123456"]
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: []) else
return
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) (data, response, error) in
if let response = response
print(response)
if let data = data
do
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
catch
print(error)
.resume()
【讨论】:
非常感谢朋友,一定要把这个作为正确答案! 如果只有 Apple 的文档会发布像这样完整的实际使用示例。 :/。谢谢。 请告诉我,如果我也将图像上传到后端?我无法发布带有数据的图像,我收到状态码 --> 400【参考方案2】:尝试运行此函数并打印响应,它在 Swift 4.0 中。
在这里,我准备了可编码的结构:
struct LoginData: Codable
var code: Int?
var message: String?
var status: String?
var token: String?
var data: DataSet?
struct DataSet: Codable
var email : String?
var contactNo : String?
var firstName : String?
var lastName: String?
var dob : String?
var gender : String?
var address: String?
var city : String?
var state : String?
var country : String?
var zip : String?
var username: String?
如果您的响应打印正确,则将其传递给您的 viewController。
func loginWS(parameters:[String:String], completionHandler: @escaping (Any?) -> Swift.Void)
guard let gitUrl = URL(string: BASE_URL+ACTION_URL) else return
print(gitUrl)
let request = NSMutableURLRequest(url: gitUrl)
// uncomment this and add auth token, if your project needs.
// let config = URLSessionConfiguration.default
// let authString = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywiUGFzc3dvcmQiOiIkMmEkMTAkYVhpVm9wU3JSLjBPYmdMMUk2RU5zdU9LQzlFR0ZqNzEzay5ta1pDcENpMTI3MG1VLzR3SUsiLCJpYXQiOjE1MTczOTc5MjV9.JaSh3FvpAxFxbq8z_aZ_4OhrWO-ytBQNu6A-Fw4pZBY"
// config.httpAdditionalHeaders = ["Authorization" : authString]
let session = URLSession.shared
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = try! JSONSerialization.data(withJSONObject: parameters, options: [])
let task = session.dataTask(with: request as URLRequest) data, response, error in
guard let data = data else return
do
// let decoder = JSONDecoder()
// here replace LoginData with your codable structure.
let gitData = try JSONDecoder().decode(LoginData.self, from: data)
print("response data:", gitData)
completionHandler(gitData)
catch let err
print("Err", err)
.resume()
【讨论】:
【参考方案3】:这是一个兼容 Swift 4 和 Swift 5 的完整解决方案示例。
Endpoint
创建网址
struct Endpoint
let path: String
let queryItems: [URLQueryItem]?
extension Endpoint
var url: URL?
var components = URLComponents()
components.scheme = "https"
components.host = "YOUR_HOST"
components.path = path
components.queryItems = queryItems
return components.url
User
请求正文的对象模型
struct User: Encodable
let name: String
let surname: String
let age: Int
// this is to customise init
init(name: String,
surname: String,
age: Int)
self.name = name
self.surname = surname
self.age = age
enum CodingKeys: String, CodingKey
case name, surname, age
UserResponse
http响应模型来自API
struct UserResponse: Decodable
let message: String
let userId: String?
enum CodingKeys: String, CodingKey
case message, userId = "user_id" // API returns userId as "user_id"
APIClient
向我们的 api 发出 http 请求
protocol APIClientProtocol: Any
func sendUser(_ user: User, completionBlock: @escaping (_ userResponse: UserResponse?, _ error: APIClient.Error?) -> Void)
class APIClient: APIClientProtocol
fileprivate let defaultSession: URLSession =
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 10.0
configuration.timeoutIntervalForResource = 10.0
return URLSession(configuration: configuration, delegate: nil, delegateQueue: nil)
()
public init()
public func uploadUser(_ user: User, completionBlock: @escaping (UserResponse?, APIClient.Error?) -> Void)
guard let url = Endpoint(path: "/user/upload", queryItems: nil).url else
completionBlock(nil, .brokenURL)
return
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
do
let jsonData = try JSONEncoder().encode(user)
urlRequest.httpBody = jsonData
catch
completionBlock(nil, .serialization(error.localizedDescription))
return
let task = defaultSession.dataTask(with: urlRequest) data, urlResponse, error in
if let error = error
completionBlock(nil, .http(error.localizedDescription))
return
guard let httpResponse = urlResponse as? HTTPURLResponse else
return
if httpResponse.statusCode == 200
guard let data = data else
return
do
let userResponse = try JSONDecoder().decode(UserResponse.self, from: data)
completionBlock(userResponse, nil)
catch let error
completionBlock(nil, .serialization(error.localizedDescription))
else
completionBlock(nil, .http("Status failed!"))
task.resume()
extension APIClient
enum Error: Swift.Error, Equatable
case brokenURL
case serialization(String)
case http(String)
【讨论】:
“Content-Type”和“Accept”在请求中都是强制性的吗?我只是想知道。我们不能只通过“接受”吗?【参考方案4】:发布类
func post(params : Dictionary<String, String>, url : String)
var request = NSMutableURLRequest(URL: NSURL(string: url))
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var task = session.dataTaskWithRequest(request, completionHandler: data, response, error -> Void in
println("Response: \(response)")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
if(err != nil)
println(err!.localizedDescription)
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: '\(jsonStr)'")
else
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON = json
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
var success = parseJSON["success"] as? Int
println("Succes: \(success)")
else
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: \(jsonStr)")
)
task.resume()
像这样调用这个方法
self.post(["username":"jameson", "password":"password"], url: "http://localhost:4567/login")
希望对你有帮助:)
【讨论】:
谢谢。在我添加了两个addValue
方法后,它开始为我工作!【参考方案5】:
Http 正文丢失。示例 - 将字符串参数设置为正文
let paramString = String(format:"param1=%@¶m2=%@",param1,param2)
request.httpBody = paramString.data(using: String.Encoding.utf8)
这里试试
request.httpBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
【讨论】:
我想设置字典而不是字符串 好的。它只是一个例子 将此值设置为http body NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)【参考方案6】:func getData(searchString:String,completion:@escaping(Any)->Void)
let url = "https://itunes.apple.com/search?term="+searchString
URLSession.shared.dataTask(with: URL.init(string: url)!)(data,response,err) in
if let responsedata = data
DispatchQueue.main.async
completion(responsedata)
.resume()
【讨论】:
考虑至少简要说明您在此处所做的工作,以及您认为导致原始问题的原因。非常感谢。【参考方案7】:试试这个:(Swift 4.2)
public func submitDelivery(delivery:DeliveryModal,responseCode:String,completion:@escaping SubmitCompletionBlock)
let urlString = BaseURL.getURL(urlType: .submit(responseCode))
guard let url = URL(string: urlString) else return
var request : URLRequest = URLRequest(url: url)
request.httpMethod = HttpMethod.post.rawValue
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
do
let jsonData = try encoder.encode(delivery)
request.httpBody = jsonData
catch
print(error.localizedDescription)
completion(nil,nil,NSError.init())
let dataTask = URLSession.shared.dataTask(with: request)
data,response,error in
guard let data = data else
completion(nil,response,NSError.init())
return
do
let data = try JSONDecoder().decode(DeliverySubmitResponseModal.self, from: data)
DispatchQueue.main.async
completion(data,response,error)
catch let error
debugPrint(error.localizedDescription)
dataTask.resume()
【讨论】:
以上是关于如何在 Swift 中发出 NSURLSession POST 请求的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Alamofire 请求 swift 3 上发出警报
如何在 iOS 应用程序的后台发出间歇性 HTTP POST 请求 - Swift