如何通过API请求中的QSYS2.HTTP_POST(_BLOB)_VERBOSE使用表单数据发送大文件?版本7.4

前端开发 2026-07-10

我有一个任务要通过API请求上传一个150MB的 CSV文件。
https://direct.broadsign.com/api/v1/docs/#/Audience/post_api_v1_audience_csv

它的Postman CLI看起来是这样的:
postman request POST 'https://direct.broadsign.com/api/v1/audience/csv'
--header 'Content-Type: text/csv'
--header 'Accept: application/json'
--header 'Cookie: bssta=true; session=.xxxx'
--from 'csv_file=@/ifspath/audience.csv'

这直接来自Broadsign的开发者。
我用Python让它跑起来:

url = "https://direct.broadsign.com/api/v1/audience/csv"
headers = {
        "Accept": "application/json",
        "Cookie": f"bssta=true; session={token}"
    }


with open("audience.csv", "rb") as f:
        files = {
            "csv_file": ("audience.csv", f, "text/csv")
        }
        response = requests.post(url, headers=headers, files=files)

我在一个函数里先拿到令牌,能够工作。
现在我必须在IBM i上实现。
我用Copilot和 Claude给出建议,但都没成功。
我找到了这个 RPG API Express ,但它是一个产品,我大概不会买,它应该没有它也能工作,对吗? 总之,我还没找到一个与我的情况匹配的示例。

我现在的情况是这样的

D SNDURL       S                   SQLTYPE(CLOB:2048)
D SNDHDR       S                   SQLTYPE(CLOB:8192)
D SNDBDY       S                   SQLTYPE(CLOB:16773100)
D RSPHDR       S                   SQLTYPE(CLOB:65535) CCSID(1208)
D RSPBDY       S                   SQLTYPE(BLOB_FILE)
D csvFile      S                   SQLTYPE(BLOB_FILE)
D url          S             100A
D options      s            1000A

url ='https://direct.broadsign.com/api/v1/audience/csv';
options= '{"headers":{"Content-Type":"text/csv",' +
                     '"Accept":"application/json",' +
                     '"Cookie":" bssta=true; session='+%TRIM(token) + '"}}';
RSPBDY_Name = '/ifspath/response.txt';
RSPBDY2_NL   = %LEN(%TRIMR(RSPBDY_Name));
RSPBDY2_FO   = SQFOVR;

csvFile_Name = '/ifspath/audience.csv';
csvFile_NL = %LEN(%TRIMR(csvFile_Name));
csvFile_FO = SQFRD;

SNDURL_DATA = %TRIM(URL);
SNDURL_LEN = %LEN(%TRIMR(SNDURL_DATA));
SNDHDR_DATA = %TRIM(options);
SNDHDR_LEN = %LEN(%TRIMR(SNDHDR_DATA));
exec sql  SELECT   RESPONSE_MESSAGE,
              CAST(RESPONSE_HTTP_HEADER  AS CLOB(1000000))
          INTO      :RSPBDY, :RSPHDR
          FROM      TABLE( QSYS2.HTTP_POST_BLOB_VERBOSE(
                       CAST(:SNDURL AS VARCHAR(2048)),
                     :csvFile,
                    CAST (:SNDHDR AS CLOB(10K))));

我得到401: Unauthorized,错误说问题出在 "Cookie" 参数。
我去掉 "bssta=true;" 这一部分后,返回400: Bad Request Error。
"The browser (or proxy) sent a request that this server could not understand."
所以不管怎么说,在Postman和 Python里 bssta都不是问题,在IBM i上就是有问题。
我不确定发送文件的方式是不是问题,还是缺少bssta部分,还是我怎样设置BLOB_FILE?

之所以使用BLOB_FILE,是因为CSV文件有150MB。qsys2.HTTP可以发送最多2 GB http_post_blob_verbose Documentation IBM
我不能在RPG-Field中做到,因为上限只有16MB。正如文档所示,RESPONSE_MESSAGE_DATA也是一个BLOB,因此我也把它定义成一个并且可以在IFS中读取。
也许这就是这里的问题?
我不确定我还缺少什么,另外的问题是我应该把File={"audience.csv",file,"text/csv"} 这部分放在哪里?
主体不能同时包含Blob_file和 字符串。在Python中它是一个元组。
据我所知,"text/csv" 已经在Content-type参数中覆盖,对吗?

任何建议或帮助都将不胜感激。

解决方案

我解决了:
http_post_blob会发送原始二进制。如果我要对接一个期望multipart/form-data的端点,我必须告诉端点它是什么类型的文件。因此,它在该二进制数据中需要一个envelope。
要构造这个envelope你必须写一个boundary。
https://medium.com/@muhebollah.diu/understanding-multipart-form-data-the-ultimate-guide-for-beginners-fd039c04553d
https://www.codelessgenie.com/blog/what-does-webkitformboundary-mean/

就我而言,我的程序在写入CSV内容。在写入数据之前我先写好multipart/forms的头部。
然后是CSV数据本身(表头和行),再用一个尾部收尾,尾部其实就是边界。
如果数据大于16MB,我也使用上述方法,使用blob_file的 sqltype。

该文件应具有1208的 CCSID(UTF8)。
需要改变的是头部中的Content-Type。把 "text/csv" 替换为 "multipart/form-data; boundary=ExampleBoundaryString",并在envelope的头部添加 "Content-Type: text/csv"。

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="csv_file"; filename="audience.csv"
Content-Type: text/csv

Screen ID,Reference ID,Screen Name,Address,Lat/long,Start Date,End Date,Start Time,
End Time,Mon,Tue,Wed,Thu,Fri,Sat,Sun,Total audience/hour
12345,,Test Screen,,,2026-04-21,2026-04-21,00:00:00,00:59:59,0,1,0,,0,0,0,18
12345,,Test Screen,,,,,,,,,,,,,,90

------WebKitFormBoundary7MA4YWxkTrZu0gW--

HTTP头应如下所示:

{"headers":{
"Content-Type":"multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW", "Accept":"application/json","Cookie":"session=xxx"
}}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章