基本的にHTTPPOST(multipart / form-data)を受信し、ペイロードをルーティングしてからHTTP POST(multipart / form-data)でペイロードを送信するMule3.2の構成に問題があります。Muleでその種のタスクをどの程度正確に実行しますか?
以下は私の構成の一部です
<flow name="UserBridgeFlow" doc:name="UserBridgeFlow">
<inbound-endpoint address="http://${local.server}/${user.context}/" exchange-pattern="request-response" connector-ref="STD_HTTP_CONNECTOR" doc:name="User Endpoint"/>
<echo-component doc:name="Echo"/>
<transformer ref="RouteTransformer" doc:name="Transformer Reference"/>
<response>
<message-properties-transformer overwrite="true" doc:name="Message Properties">
<add-message-property key="Access-Control-Allow-Origin" value="*"/>
</message-properties-transformer>
</response>
<response>
<echo-component doc:name="Echo"/>
</response>
<http:outbound-endpoint exchange-pattern="request-response" address="http://${user.server}/#[header:OUTBOUND:real.path]" doc:name="HTTP User"/>
<default-exception-strategy>
<processor-chain>
<logger level="INFO" doc:name="Logger"/>
</processor-chain>
</default-exception-strategy>
</flow>
上記の構成では、他のエンドポイントに到達するとバイナリデータが常に破損し、ブラウザ(呼び出し元のエンドポイント)でこのエラーが発生します。「プレーンテキストドキュメントの文字エンコードが宣言されていません。ドキュメントは一部で文字化けしたテキストでレンダリングされますドキュメントにUS-ASCII範囲外の文字が含まれている場合は、ブラウザの構成。ファイルの文字エンコードを転送プロトコルで宣言するか、ファイルでエンコード署名としてバイトオーダーマークを使用する必要があります。」
-更新された構成-
<context:property-placeholder location="classpath:/mule.properties"/>
<custom-transformer class="id.co.zire.ebs.mule.transformer.RouteTransformer" name="RouteTransformer" doc:name="RouteTransformer"/>
<http:connector name="STD_HTTP_CONNECTOR" enableCookies="true" validateConnections="true" clientSoTimeout="20000" serverSoTimeout="10000" doc:name="HTTP\HTTPS">
<dispatcher-threading-profile maxThreadsActive="50" maxBufferSize="150"/>
<reconnect count="3" frequency="2000"/>
</http:connector>
<flow name="HTTPBridgeFlow" doc:name="HTTPBridgeFlow">
<composite-source>
<inbound-endpoint exchange-pattern="request-response" address="http://${local.server}/${user.context}/" encoding="ISO-8859-1" connector-ref="STD_HTTP_CONNECTOR" doc:name="User Endpoint"/>
<inbound-endpoint exchange-pattern="request-response" address="http://${local.server}/${cms.context}/" encoding="ISO-8859-1" connector-ref="STD_HTTP_CONNECTOR" doc:name="CMS Endpoint"/>
<inbound-endpoint exchange-pattern="request-response" address="http://${local.server}/${ads.context}/" encoding="ISO-8859-1" connector-ref="STD_HTTP_CONNECTOR" doc:name="Ads Endpoint"/>
</composite-source>
<echo-component doc:name="Echo"/>
<transformer ref="RouteTransformer" doc:name="Transform Header"/>
<set-property propertyName="http.method" value="#[header:INBOUND:http.method]" doc:name="Copy HTTP method"/>
<flow-ref name="HTTPResponseFlow" doc:name="HTTP Flow Reference"/>
</flow>
<sub-flow name="HTTPResponseFlow" doc:name="HTTPResponseFlow">
<logger message="Payload Output : #[message.payload]" level="INFO" doc:name="Logger"/>
<choice doc:name="Choice">
<when expression="message.inboundProperties['http.context.path'] contains '${user.context}'">
<processor-chain>
<http:outbound-endpoint exchange-pattern="request-response" address="http://${user.server}/#[message.inboundProperties['http.relative.path']]" responseTimeout="120000" doc:name="HTTP User"/>
</processor-chain>
</when>
<when expression="message.inboundProperties['http.context.path'] contains '${cms.context}'">
<processor-chain>
<http:outbound-endpoint exchange-pattern="request-response" address="http://${cms.server}/#[message.inboundProperties['http.relative.path']]" responseTimeout="120000" doc:name="HTTP CMS"/>
</processor-chain>
</when>
<when expression="message.inboundProperties['http.context.path'] contains '${ads.context}'">
<processor-chain>
<http:outbound-endpoint exchange-pattern="request-response" address="http://${ads.server}/#[message.inboundProperties['http.relative.path']]" responseTimeout="120000" doc:name="HTTP Ads"/>
</processor-chain>
</when>
</choice>
<echo-component doc:name="Echo"/>
<message-properties-transformer doc:name="Set Cross-Domain Request Allowed">
<add-message-property key="Access-Control-Allow-Origin" value="*"/>
<add-message-property key="Access-Control-Allow-Methods" value="GET, POST, OPTIONS"/>
<add-message-property key="Access-Control-Max-Age" value="1000"/>
<add-message-property key="Access-Control-Allow-Headers" value="Content-Type"/>
</message-properties-transformer>
</sub-flow>
OK、これでほとんどの構成を変更しました。HTTPPOSTメッセージ本文に含まれているバイナリデータを渡す際に問題が発生しました。Muleは、バイトをアウトバウンドエンドポイントに渡す前にバイトを変更しているようです。ペイロードを手動で取得し、ペイロードからバイナリデータを解析するカスタムトランスフォーマーを作成しました(ペイロードタイプは文字列です)が、ペイロードから取得されたバイナリデータはすでに変更されています。たとえば、以下は16進数の元のファイルバイトの一部です。
ff d8 ff e0 00 10 4a 46(ÿØÿà..JF)
しかし、Muleは次のように変換されます。
3f 3f 3f 3f 00 10 4a 46(???? .. JF)
エンコーディングの問題だと思います。おそらくMuleは自動的にUTF-8に変換します。
--RouteTransformer.java-
public class RouteTransformer extends AbstractMessageTransformer{
private static final String MULE_CONFIG = "/mule.properties";
private static final String CLIENT_IP = "MULE_REMOTE_CLIENT_ADDRESS";
private static final String CLIENT_IP_HEADER = "Client-Ip";
private static final String IP_REGEX = "/?((\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3}))(:(\\d{1,5}))?";
private final String[] PASSING_HEADER;
public RouteTransformer() throws IOException{
Properties prop = new Properties();
prop.load(getClass().getResourceAsStream(MULE_CONFIG));
PASSING_HEADER = prop.getProperty("passing-header").split("\\s*,\\s*");
}
public Object transformMessage(MuleMessage message, String outputEncoding) throws TransformerException{
// Copy 'passing' header
for(int i=PASSING_HEADER.length; --i>=0; ){
String headerName = PASSING_HEADER[i];
Object val = message.getInboundProperty(headerName);
if(headerName.equals(CLIENT_IP)){
String s = (String) val;
Pattern p = Pattern.compile(IP_REGEX);
Matcher m = p.matcher(s);
if(!m.matches()) continue;
else{
headerName = CLIENT_IP_HEADER;
val = m.group(1);
}
}
if(val != null) message.setOutboundProperty(headerName, val);
}
// Routing message
String requestString = message.getInboundProperty("http.request");
String contextPath = message.getInboundProperty("http.context.path");
if(requestString != null && contextPath != null)
message.setOutboundProperty("http.real.path", requestString.substring(contextPath.length()));
return message;
}
}
--マルチパート/フォームデータの例-
-----------------------------20037128598723
Content-Disposition: form-data; name="name"
Angga
-----------------------------20037128598723
Content-Disposition: form-data; name="adsImage"; filename="Penguins.jpg"
Content-Type: image/jpeg
ÿØÿà..JF -- and the rest of bytes --
誰かがいくつかの解決策をもたらすことができることを願っています。ありがとう