再び私。技術的な演習として、WSO2 ESB を使用して一部の Web トラフィックをプロキシしようとしています。具体的には、Web トラフィックをプロキシし、返された応答をその場で次のように変更しようとしています。
- ESB に HTTP リクエストを受信させる
- リクエストを特定のサーバーにプロキシする
- 応答を受け取る
- 「sad」という単語を見つけて「happy」に置き換えます (大文字と小文字を区別しない正規表現)
- 変更された応答をブラウザに返す
これは単純な正規表現または XSLT 操作だと思う人もいるかもしれませんが、これは私が思っていたよりもはるかに難しいことが判明しています。今のところ、これは私が使用しているプロキシ スクリプトです...
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="PassProxy"
transports="https http"
startOnLoad="true"
trace="disable">
<description>Route content from a web server through the ESB service and alter it</description>
<target>
<endpoint>
<address uri="http://server.yoyodyne.com/"/>
</endpoint>
<inSequence/>
<outSequence>
<property name="TheContentIncludingTheSoapEnvelope" expression="."/>
<property xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns="http://org.apache.synapse/xsd"
name="TheContentFromSoapBodyButNotReally"
expression="//soapenv:Envelope/soapenv:Body/*"/>
<property name="TheContent"
value="An initial value that should be replaced"
scope="default"
type="STRING"/>
<enrich>
<source type="body" clone="true"/>
<target type="property" property="TheContent"/>
</enrich>
<property name="ContentType" expression="$trp:Content-Type"/>
<property name="ContentLength" expression="$trp:Content-Length"/>
<log level="custom">
<property name="ContentType" expression="$trp:Content-Type"/>
<property name="ContentLength" expression="$trp:Content-Length"/>
<property name="MessageVar" value="TheContent"/>
<property name="TargetMessage" expression="get-property('TheContent')"/>
</log>
<script language="js">
//hack because xpath fn:replace does not work in property tags and fn:translate works on chars not whole strings
var contentType=mc.getProperty('ContentType');
var contentObject=mc.getProperty('TheContent'); //how to get the text of this? And do it in un-escaped format???
if(/text/i.test(contentType)) {
if(!contentObject) {
mc.setProperty('TheAlteredContent','Well that didn\'t work as expected');
} else {
if(typeof contentObject == 'object' || typeof contentObject == 'undefined') {
var returnMessage='';
for (var key in contentObject) {
returnMessage=returnMessage+'found key "'+key+'"\n';
} //end object key for
returnMessage='Can\'t work with this type of input - '+typeof contentObject+'n\Available keys to try:\n'+returnMessage;
contentObject=returnMessage;
} else {
contentObject=contentObject.replaceAll('sad', 'happy');
//more regex statements to go here
} //end typeof if
} //end property check if
} else {
//not text - do nothing
contentObject='binary content (I think). Found content type of "'+contentType+'"';
} //end content type check if
//send the content back
mc.setProperty('TheAlteredContent',contentObject);
</script>
<enrich>
<!-- need to figure out how to replace the content and not append to the end of it. Replace tag on target keeps getting removed for some reason -->
<source type="property" property="TheAlteredContent" clone="true"/>
<target type="body"/>
</enrich>
<!-- doctype headers in the HTML cause logging to fail, so no debugging for you -->
<!--<log level="full"/>-->
<send/>
</outSequence>
</target>
</proxy>
確かに、enrich 操作を使用することはおそらくこれを処理する最良の方法ではありませんが、当時は良いアイデアのように思えました。最終的に何が起こるかというと、応答の HTML 部分がエスケープされたコンテンツを持つオブジェクトとして JS コードに渡される (または渡される???) ことです。「contentObject」変数はオブジェクトであるため、正規表現は失敗します。toString() を使用して "contentObject" を強制的に文字列にすることもできません。機能したとしても、HTML コンテンツはエスケープされた形式のままであり、HTML 形式のままにしておく必要がある HTML コードにエスケープされたエントリが含まれている可能性があるため、元に戻すには問題が生じる可能性があります。ここでの最後の問題は、「TheAlteredContent」のプロパティのコンテンツがコンテンツに追加され、属性が「action=replace」であっても置き換えられないことです。
これを行うためのより良い方法、または上記のコードを機能させる方法を知っている人はいますか?