質問
〇Content-Type: application/jsonの場合にエンコーディングの指定は必要か。
〇根本的にjson形式のデータをPOSTする方法が間違っているか。
以下の現象に関して、解決策や問題点が思い当たる方がいらっしゃれば、ぜひ教えていただけますでしょうか。
よろしくお願いいたします。
実現したいこと
C#
1// POST: api/PushMsg 2 [HttpPost] 3 public bool PushMessage([FromBody] string value) 4 { 5 try 6 { 7 Logger.log(Logger.INFO, "Apnsサーバーに送信処理開始(クライアントから受信直後)"); 8 Logger.log(Logger.INFO, value, true); 9 PushMessage msg = JsonConvert.DeserializeObject<PushMessage>(value); 10 var ret = SendMessage(msg); 11 Logger.log(Logger.INFO, "Apnsサーバーに送信正常終了", true); 12 return ret.Result; 13 } 14 catch(Exception ex) 15 { 16 Logger.log(Logger.ERROR, "送信異常終了 => " + ex.Message, true); 17 return false; 18 } 19 }
URL:http://IPアドレス:ポート番号/サーバー名/API/PushMsg
Header:Content-Type: application/json\r\n
HTTPBody:以下の文字列(CString)をバッファ(char*)の格納して ”POST”
{"userNo":4,"member":[12,16],"category":"comment","detail":{"commentId":10282,"talkId":36},"title":"新規コメント","message":"新規コメントがあります。","appId":"製品識別用ID","sound":"default"}
で上記APIにjson形式の文字列をPOSTしたい
発生している問題・エラーメッセージ
System.Text.DecoderFallbackException: Unable to translate bytes [82][DC] at index 116 from specified code page to Unicode.……
Header: application/json; charset=UNICODE
とすると、API/PushMsgにたどり着いて文字列を渡すことができるが、
引数で受け取る文字列が文字化けしてしまった。
例)≻獵牥潎㨢㜳∬敭扭牥㨢ㅛ崲∬灡䥰≤∺獡牴獯慴敧䄮瑳潲慔歬Ⱒ琢瑩敬㨢丢睥敍獳条≥∬敭獳条≥∺潙⁵慨敶愠丠睥䴠獥慳敧∮∬慣整潧祲㨢挢浯敭瑮Ⱒ搢瑥楡≬笺挢浯敭瑮摉㨢㤱㠶ⰰ琢污䥫≤㈺紱∬潳湵≤∺敤慦汵≴}
試したこと
検証用にPOSTされた文字列を受け取って、そのまま返すだけのAPIを用意して検証してみた。↓
C#
1[HttpPost("TestFunc")] 2 public string TestFunc([FromBody] string value) 3 { 4 var postData = ""; 5 postData = value; 6 Logger.log(Logger.INFO, " postData :" + postData, true); 7 8 return postData != null ? postData : "no post body"; 9 }
URL:http://IPアドレス:ポート番号/サーバー名/API/PushMsg/TestFunc
Header:Content-Type: text/plain\r\n
HTTPBody:同様
これを実行してデバックすると、
postData :{"userNo":37,"member":[12],"appId":"アプリ識別用ID","title":"新規メッセージ","message":"新規のメッセージがあります。","category":"comment","detail":{"commentId":19802,"talkId":21},"sound":"default"}
となり文字化け等起こらず、成功しました。
サーバーログでも確認済みです。
MFC側POST処理
C++
1BOOL NotifyiOS( CString strConnectString, CString strBody ) 2{ 3 // jsonファイル読み取り 4 CString strLocalTextFullPath = _T( "jsonファイルのパス" ); 5 6 // 文字コード指定してファイルから読み取り 7 strBody = _T( "" ); 8 FILE *pFile; 9 fopen_s( &pFile, CT2A( strLocalTextFullPath ), "r, ccs=UTF-8" ); 10 //fopen_s( &pFile, CT2A( strLocalTextFullPath ), "r, ccs=UTF-16LE" ); 11 if ( NULL != pFile ) { 12 CStdioFile file( pFile ); 13 CString strJsonText; 14 while ( file.ReadString( strJsonText ) ) { 15 TRACE( L"%s\n", strJsonText ); 16 strBody = strJsonText; 17 } 18 file.Close( ); 19 } 20 fclose( pFile ); 21 22 // バッファ確保、データコピー 23 DWORD nBuff = strBody.GetLength() * sizeof( TCHAR ); 24 char *pBuff = NULL; 25 pBuff = (char *)malloc( nBuff ); 26 if ( NULL == pBuff ) { 27 return FALSE; 28 } 29 strcpy_s( pBuff, nBuff, CT2A( strBody, CP_UTF8 ) ); 30 strcpy_s( pBuff, nBuff, CT2A( strBody ) ); // こうするとTestFuncで文字化け 31 32 CString strURL = strConnectString; 33 34 CString strHttpRes; 35 int nResult = -1; 36 nResult = HttpiOSNotify( strHttpRes, CT2A( strURL ), pBuff, nBuff, 300000 ); // POST 37 38 if ( 0 > nResult ) { 39 free( pBuff ); 40 return FALSE; 41 } 42 43 free( pBuff ); 44 return TRUE; 45} 46 47int HttpiOSNotify( CString &csRet, const char *szURL, void *pData, int nData, DWORD Timeout, const char *szProxyServer, const char *szProxyUser, const char *szProxyPassword ) 48{ 49 int nRet; 50 CActiveBuffer Buff; 51 52 if ( FALSE == Buff.Init( 32768, 32768 ) ) return 0; 53 54 nRet = HttpiOSNotify( Buff, szURL, pData, nData, Timeout, szProxyServer, szProxyUser, szProxyPassword ); 55 if ( 1 > nRet ) { 56 Buff.Close( ); 57 return nRet; 58 } 59 60 Buff.Add( "\0", 1 ); 61 62 csRet = (char *)Buff.DataP(); 63 Buff.Close( ); 64 65 return nRet; 66} 67 68int HttpiOSNotify( CActiveBuffer &Buff, const char *szURL, void *pData, int nData, DWORD Timeout, const char *szProxyServer, const char *szProxyUser, const char *szProxyPassword ) 69{ 70 char szWork[ 512 ]; 71 DWORD Timeout2; 72 CWinInetHttpThread *thHttpGet; 73 CString strHeader; 74 CActiveBuffer Body; 75 76 if ( FALSE == Body.Init( 131072, 131072 ) ) return -1; 77 78 Timeout2 = Timeout / 2; 79 if ( 30000 > Timeout2 ) Timeout2 = 30000; 80 81 //strHeader = _T( "" ); // ヘッダー指定なし 82 strHeader = _T( "Content-Type: application/json\n" ); // × 83 //strHeader = _T( "Content-Type: application/json; charset=UTF-8\r\n" ); // × 84 //strHeader = _T( "Content-Type: application/json; charset=UNICODE\r\n" ); // 〇 85 //strHeader = _T( "Content-Type: application/json; charset=UTF-16\r\n" ); // 〇 86 //strHeader = _T( "Content-Type: text/plain\r\n" ); // TestFunc用 87 88 Body.Add( pData, (DWORD)nData ); 89 90 thHttpGet = new CWinInetHttpThread( CString( szURL ), Timeout2, Timeout2, Timeout2, strHeader, Body.DataP( ), Body.GetLength( ), HttpReceiveToBuffer, &Buff, NULL, 0, CString( szProxyServer ), CString( szProxyUser ), CString( szProxyPassword ) ); 91 92 if ( WAIT_OBJECT_0 != thHttpGet->WaitForThread( Timeout ) ) { 93 thHttpGet->SetCancel( ); 94 thHttpGet->WaitForEndThread( ); 95 delete thHttpGet; 96 Body.Close( ); 97 return -12002; 98 } 99 100 thHttpGet->WaitForEndThread( ); 101 102 if ( true == thHttpGet->GetErrInfo( )->IsError( ) ) { 103 int nErr = thHttpGet->GetErrInfo( )->ErrCode( ); 104 delete thHttpGet; 105 Body.Close( ); 106 return -nErr; 107 } 108 109 delete thHttpGet; 110 return (int)Buff.GetLength( ); 111} 112 113その他一般的なHTTPセッション処理
【現状の原因調査結果】
TestFuncでは文字化けせず、PushMessageでは文字化けしてしまう理由がよくわかりません。
ちなみにコマンドプロンプトから同じjson文字列のデータをポストすると文字化けもなく、成功します。
例)curl -X POST -H "Content-Type: application/json" -d @iOSNotifyInfo.json "http://192.168.1.175:80/ApnsPushServerDebug/API/PushMsg" -v
補足情報(FW/ツールのバージョンなど)
【開発環境】
(アプリ)
フレームワーク:MFC
言語:C++
プロジェクトの文字セット:UNICODE
(サーバ)
フレームワーク:.Net Core 3.1
言語:C#

回答2件
あなたの回答
tips
プレビュー