iOS向Node.js(v19.0.1)发送含非ISO-8859-1字符的POST请求报错求助
解决请求头含特殊字符的POST请求失败问题
问题根源
HTTP/1.1 标准规定请求头字段值仅允许包含 ISO-8859-1 字符集内的可打印字符,你遇到的右单引号、表情符号、特殊符号等都属于非ISO-8859-1字符,服务器会直接拒绝这类不符合规范的请求,这也是Postman测试同样失败的原因。
方案1:将数据移至请求体(推荐,后端修改极小)
虽然你担心后端修改,但这个方案的后端改动非常简单,完全不需要复杂的JavaScript知识:
前端修改(Swift/Alamofire)
把原来放在请求头的参数移到请求体中:
import Foundation import Alamofire func updateNote(date: String, title: String, note: String, id: String) { // 构造请求体参数 let parameters: [String: Any] = [ "title": title, "date": date, "note": note, "id": id ] // 发送请求时传入parameters,Alamofire会自动编码为form-data格式 AF.request("http://\(networkIP):8081/update", method: .post, parameters: parameters, encoding: URLEncoding.httpBody) .resume() }
后端修改(Node.js)
如果你的后端用Express框架,只需要添加一行解析请求体的代码,再把获取数据的方式从headers改成body即可:
const express = require('express'); const app = express(); // 添加这行代码,用于解析form-data格式的请求体 app.use(express.urlencoded({ extended: true })); app.post('/update', (req, res) => { // 原来的req.headers.title改成req.body.title,其他字段同理 const title = req.body.title; const date = req.body.date; const note = req.body.note; const id = req.body.id; // 这里保留你原来的业务逻辑,不需要改动 // ... res.send('success'); }); app.listen(8081);
这个方案不仅彻底解决字符问题,还符合HTTP规范,后续不会再出现类似兼容问题。
方案2:对请求头字段值进行RFC 2047编码(需后端配合解码)
如果实在不想调整后端核心逻辑,只能对特殊字符进行编码,让请求头符合ISO-8859-1规范,但后端必须解码才能拿到原始内容:
前端编码实现
在Swift中新增一个RFC 2047编码函数:
import Foundation // 将字符串转为RFC 2047格式的Base64编码 func encodeHeaderValue(_ value: String) -> String? { guard let data = value.data(using: .utf8) else { return nil } let base64Str = data.base64EncodedString() return "=?UTF-8?B?\(base64Str)?=" } // 修改请求函数 func updateNote(date: String, title: String, note: String, id: String) { let encodedTitle = encodeHeaderValue(title) ?? title let encodedNote = encodeHeaderValue(note) ?? note let headers: HTTPHeaders = [ "title" : encodedTitle, "date" : date, "note" : encodedNote, "id" : id ] AF.request("http://\(networkIP):8081/update", method: .post, encoding: URLEncoding.httpBody, headers: headers) .resume() }
后端解码(必须添加,否则无法获取原始内容)
在Node.js中新增解码逻辑:
// 新增解码函数 function decodeRFC2047(str) { return str.replace(/=\?UTF-8\?B\?(.*?)\?=/g, (match, base64) => { return Buffer.from(base64, 'base64').toString('utf8'); }); } // 在接口中使用解码后的字段 app.post('/update', (req, res) => { const title = decodeRFC2047(req.headers.title); const note = decodeRFC2047(req.headers.note); // ...业务逻辑 });
但这个方案不符合HTTP规范,后续仍可能出现其他兼容问题,所以还是优先推荐方案1。
内容的提问来源于stack exchange,提问作者eric_b_231
相关产品推荐
相关产品推荐

