图像未通过POST完整传输到服务器



我通过POST将文本和图片发送到服务器。文字输入正确,但图片不完整。图片的10%是正确显示的,其他的只是灰色背景。CCD_ 2使用CCD_ 3将图像文件转换为文本。

似乎Swift执行转换时出错,或者服务器没有完全接收到数据。但我已经提高了POST的限制,这没有帮助。我还用compressionQuality更改了图像压缩值,但没有帮助。

来自视图文件的代码:

Button(action: {
self.checkBoxStatus = false
let uiImage: UIImage = self.selectedImage.asUIImage()
let imageData: Data = uiImage.jpegData(compressionQuality: 0.9) ?? Data()
let imageStr: String = imageData.base64EncodedString()
let shareHelper = ShareHelper(message: validateForm.content, user: validateForm.user, email: validateForm.email, media: imageStr)
shareHelper.RequestPost { (dataString) in
self.checkRequestStatus = true
validateForm.content = ""
validateForm.user = ""
validateForm.email = ""
validateForm.media = ""
self.selectedImage = Image("")
}
}, label: {
Text("Send")
})

如何修复?

p.S.:

POST请求代码:

import Foundation
class ShareHelper {
var dataString: String = ""
var newsMessage: String
var newsUser: String
var newsEmail: String
var newsMedia: String
let newsAPI: String = "https://example.com/api/shareNews"
init(message: String, user: String, email: String, media: String) {
self.newsMessage = message
self.newsUser = user
self.newsEmail = email
self.newsMedia = media
}
func RequestPost(completion: @escaping((String) -> Void)) {
let url = URL(string: self.newsAPI)
guard let requestUrl = url else { fatalError() }
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
let postString = "message=(self.newsMessage)&user=(self.newsUser)&email=(self.newsEmail)&media=(self.newsMedia)"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil {
return
}
if let data = data, let dataString = String(data: data, encoding: .utf8) {
DispatchQueue.main.async {
self.dataString = dataString
completion(dataString)
}
}
}
task.resume()
}
}

您可以使用SerialQueue使用Combine框架,并将图像与新闻相关的数据分开发送。

因此,这是SwiftUI视图中的按钮所在位置。您会注意到,我引入了一个视图模型来避免视图中的任何逻辑。

import SwiftUI
struct ContentView: View {
/// Used to separate the logic from the view.
@ObservedObject var viewModel = ContentViewModel()
var body: some View {
Button(action: { viewModel.sendNewsData() }) {
Text("Send")
}
}
}

这就是视图模型本身,发送数据的逻辑发生在这里。您必须单独处理新闻数据的发送。如果您需要一些帮助来使用Combine,只需在StackOverflow上问一个新问题。

import Combine
import SwiftUI
final class ContentViewModel: ObservableObject {
let networkRequestManager = NetworkRequestManager()
let image = UIImage(named: "MySpecialImage")!  // The image you want to send
var cancellables = Set<AnyCancellable>()
/// Send the news data and the image in one function
/// to be used in your SwiftUI view.
func sendNewsData() {
postImageData(of: image)
postNewsData()
}
/// Send the image on its own method.
///
/// The data encoded string printed is related
/// to your image that comes back from the api.
func postImageData(of image: UIImage) {
networkRequestManager
.sendImage(image)
.sink(
receiveCompletion: { completion in
print(completion) },
receiveValue: { data in
print(data) }) // your image
.store(in: &cancellables)
}
func postNewsData() {
// Just post your news data without the image
// for it to be sent separately.
}
}

这里是NetworkRequestManager类,它处理将编码为String的图像发送到api端点。只需根据需要更改url即可。不要忘记将与映像关联的密钥更改为与api中的相关密钥。如果你需要一个使用Combine和Cache系统取回图像的解决方案,只需在StackOverflow上问一个新问题。

import Combine
import SwiftUI
final class NetworkRequestManager {
/// Send the image in a serial queue to not obstruct the main queue.
let imageSerialQueue = DispatchQueue(label: "imageSerialQueue")
/// This is where you will encode your image data to send it to your api.
func sendImage(_ image: UIImage) -> AnyPublisher<String, Error> {
let url = URL(string: "https://example.com/api/shareNews")!
let body = setupBody(with: image)
let urlRequest = setupURLRequest(url: url, body: body)
return URLSession.shared
.dataTaskPublisher(for: urlRequest)
.subscribe(on: imageSerialQueue)
.map { $0.data }
.encode(encoder: JSONEncoder())
.decode(type: String.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
/// The body related to your endpoint.
///
/// Make sure that the dictionary key matches the one in your api.
func setupBody(with image: UIImage) -> [String: Any] {
let jpegData = image.jpegData(compressionQuality: 1)
return ["newsMedia": jpegData?.base64EncodedString() as Any]
}
/// Setup the url request to send a POST method with your image
/// in a json format.
func setupURLRequest(url: URL,
body: [String: Any]) -> URLRequest {
var urlRequest = URLRequest(url: url)
urlRequest.allowsConstrainedNetworkAccess = true
urlRequest.httpMethod = "POST"
urlRequest.setValue("application/json",
forHTTPHeaderField: "Content-Type")
urlRequest.httpBody = try? JSONSerialization.data(withJSONObject: body)
return urlRequest
}
}

我在这个线程中看到了一些解决您问题的方法如何使用Swift将图像上传到iOS中的服务器?

在这个线程中,还有一些答案演示了如何通过POST方法将图像上传到服务器。

最佳实践是提供仅用于上传图像的上传api。您可以使用多部分POST来使它做得很好。然后获取带有上传图像ID的响应,并将其添加到shareNewsAPI请求中。

服务器端应按id管理图像。

对于您当前的代码,我想它运行得很好,试着询问后端开发人员如何解码您的base64 ed数据。

最新更新