图像未通过 POST 完整传输到服务器
Posted
技术标签:
【中文标题】图像未通过 POST 完整传输到服务器【英文标题】:The image is not transferred in full via POST to the server 【发布时间】:2021-04-09 09:18:10 【问题描述】:我通过POST
将文本和图片发送到服务器。文字正确,但图片不完整。 10% 的图片显示正确,其他为灰色背景。 Swift
使用base64EncodedString()
将图像文件转换为文本。
似乎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")
)
如何解决?
附:
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()
【问题讨论】:
imageStr
的大小是多少?您的请求中是否包含 Content-Length?您在服务器上获得正确的大小吗?您是使用“基本帖子”,还是使用 multipart/url 表单数据?
我在我的问题中添加了 POST 请求代码。
如何初始化类? newsMessage
是否包含 UIImage 的字符串?!
我已经更新了我的问题并添加了初始化类的代码。 newsMessage - 是字符串。
ShareHelper(message: validateForm.content, user: validateForm.user, email: validateForm.email, media: imageStr)
【参考方案1】:
您可以使用带有 SerialQueue 的组合框架,并将您的图像与与您的新闻相关的数据分开发送。
这是按钮所在的 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 时需要一些帮助,只需在 *** 上提出一个新问题即可。
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
类,它处理将编码为字符串的图像发送到您的 api 端点。只需根据需要更改 url。
不要忘记将与图像关联的键更改为与您的 api 中相关的键。如果您需要使用组合和缓存系统获取图像的解决方案,只需在 *** 上提出一个新问题。
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
【讨论】:
感谢您的代码!我明天测试一下!【参考方案2】:我在这个帖子How to upload images to a server in ios with Swift?看到了一些解决你问题的方法
在此线程中,还有一些答案演示了如何通过 POST 方法将图像上传到服务器。
【讨论】:
当然可以。我已经搜索了许多具有相同问题的帖子。但他们有Storyboard
的解决方案,我需要SwiftUI
。而且我不仅发送图像。除了图片,我还有很多文本数据要发送。所有这些都需要一键发送。
您答案中的链接非常旧。这个问题是 6 年前提出的。
LeXxy,你说得对,帖子很旧,但答案仍然相关。我也不明白 Storyboard 或 SwiftUI 与这些解决方案有什么关系,您正在谈论将图像表示数据发布到服务器【参考方案3】:
最佳做法是提供仅用于上传图片的上传 api。您可以使用多部分 POST 来使其做得很好。然后获取上传图片 ID 的响应,并将其添加到您的 shareNews
api 请求中。
服务器端应该通过 id 来管理图片。
对于您当前的代码,我猜它运行良好,请尝试询问后端开发人员他们如何解码您的 base64-ed 数据。
【讨论】:
以上是关于图像未通过 POST 完整传输到服务器的主要内容,如果未能解决你的问题,请参考以下文章
Android 相机图像未上传到服务器。使用多部分数据 Http post
通过 POST 命令将音频从 ios 流式传输到 REST 服务器