Gon*_*alo 0 php java vb6 gwt json
我想知道是否有一种从"字符串表"获取序列化字符串的方法.
我需要的是在网页表单中发布一些数据.这是我手动执行时发送的内容:
7 | 0 | 48 | https://aps2.senasa.gov.ar/embalaje-madera-web/embalajeApp/|03152A2DEBABDCE5D33BF4C88511DD1E|net.customware.gwt.dispatch.client.standard.StandardDispatchService|execute|net.customware.gwt.dispatch.shared.Action | gov.senasa.embalajemadera.shared.rpc.actions.IngresarDeclaracionJuradaAction/2514804035 | gov.senasa.embalajemadera.shared.domain.DeclaracionJurada/1628723960 | java.util.ArrayList中/ 4159755760 | gov.senasa.embalajemadera.shared.domain.TipoEmbalajeCantidad /4152068152|java.lang.Integer/3438268394|Pallet|gov.senasa.embalajemadera.shared.domain.TipoEmbalaje/309031988|java.util.HashSet/3273092938|gov.senasa.embalajemadera.shared.domain.Contenedor/1178264080|nro contenedor 1 | java.lang.Boolean/476441737 | gov.senasa.embalajemadera.shared.domain.Despachante/3149599025 | DESP || java.lang.Long/4227064769 | Treyes 8978 - CAPITAL FEDERAL | gonzalo@rsystem.com.ar | Spina Gonzalo | 45510141 | direccion destino | direccion exportador | java.util.Date/3385151746 | chasis/| gov.senasa.embalajemadera.shared.domain.Importador Exportador/918958990|gonzalo@gmail.com|46326066|gov.senasa.embalajemadera.shared.domain.DatoAduana/2671264783|NRODESPACHO|IC01|gov.senasa.embalajemadera.shared.domain.LugarDeArribo/3008903128|NROMANIIMPO|gov.senasa. embalajemadera.shared.domain.PuntoIngreso/1183502123 | 717.3 | aduana origen | Terrestre camion | merca | gov.senasa.embalajemadera.shared.domain.Pais/3238585366 |澳大利亚| AFGHANISTAN | nombre exportador | gov.senasa.embalajemadera.shared.domain .TransportePatente/1923027028 | acoplado |底盘| 1 | 2 | 3 | 4 | 1 | 5 | 6 | 7 | 0 | 0 | 8 | 1 | 9 | 0 | 10 | 1 | 10 | 10 | 11 | 10 | 12 | 0 | 0 | 11 | 10 | 126951 | 0 | 0 | 0 | 0 | 0 | 13 | 1 | 14 | 0 | 0 | 15 | 16 | 1 | 17 | 0 | 18 | 10 | 19 | 20 | ZRCrAA | 21 | 22 | 19 | 0 | 0 | 23 | 24 | 0 | 0 | 0 | 0 | 0 | 25 | 26 | 0 | 0 | 27 | VnTkM $ A | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 28 | -11 | 29 | 0 | 0 | 19 | -13 | 21 | 30 | 0 | 0 | 0 | 23 | 31 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 1 | 32 | 0 | 16 | 0 | -18 | 0 | 0 | -2 | 0 | 0 | 33 | 0 | 0 | 0 | 27 | VnTkM $ A | 0 | 34 | 35 | 0 | 0 | 0 | 10 | 24754701 | 0 | -18 | 36 | 19 | 37 | 10 | 38 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | -20 | 39 | 40 | 41 | 0 | 0 | 0 | 42 | 0 | 43 | 10 | 10 | 42 | 10 | 44 | 10 | 1 | 0 | -22 | -5 | 45 | 0 | 0 | 0 | -18 | 8 | 1 | 46 | 0 | 0 | 0 | 19 | 47 | 48 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
我已经阅读过 这篇文章,但正如您所看到的,这比文档中的示例稍微复杂一些.我无法构建有效负载.我需要一个与VB6或PHP兼容的方法,或者只是一个很好的解释,所以我可以自己编写例程.谢谢
编辑:我回答反序列化(您可能仍然需要,如果你要做的结果的东西从服务器),但你问的系列化.第一部分仍然是一个请求的反序列化,但在休息之下,我将展示如何序列化一个请求,再次使用我们在这个问题中的有限信息
它可能比文档中的示例更大,但适用相同的规则.对于像这样的请求,我们将其分解如下,分割|角色.
7
版本7.
0
没有设置标志.
48
接下来的48个令牌是字符串表,用它们构建一个数组.这些字符串将表示传递的数据类型以及实际的Java字符串.
所以我们将字符串读入String [48],然后所有剩余的数字都是引用或原语.数据类似ZRCrAA并且VnTkM$A可能是base64编码的长.将其视为字符串列表,当我们从数据开始请求对象时,我们将使用它.
正如文档所说,我们现在从第二个列表中读取引用(以...开头1|2|3|4|1|5|6|7|0|0|8...).当我们继续反序列化时,我们还需要四个东西:应用程序的url,策略的强名称,我们将要调用的服务类,以及该服务类中的方法名称.
由于这些都是字符串对象,我们将读取字符串.在com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader,读取这个的实际Java类,我们看到readString()看起来像这样:
@Override
public String readString() throws SerializationException {
return getString(readInt());
}
Run Code Online (Sandbox Code Playgroud)
首先我们读取一个int,然后使用它来查找字符串.这是getString:
@Override
protected String getString(int index) {
if (index == 0) {
return null;
}
// index is 1-based
assert (index > 0);
assert (index <= stringTable.length);
return stringTable[index - 1];
}
Run Code Online (Sandbox Code Playgroud)
现在,我们的第一个数据是基本URL,读作字符串.我们看到1我们读取的int,然后我们在上面创建的String [48]中得到第(1 - 1)个字符串:
接下来是强有力的政策名称2,我们将其视为
03152A2DEBABDCE5D33BF4C88511DD1E
服务器将使用它并找到一个名为03152A2DEBABDCE5D33BF4C88511DD1E.gwt.rpc的文件,概述了可以在服务器上创建的安全策略(以便禁止黑客在您的服务器上创建任何类型的对象).
接下来我们寻找服务类,3:
net.customware.gwt.dispatch.client.standard.StandardDispatchService
最后调用的方法是4:
执行
从这里,你需要知道什么StandardDispatchService.execute- 我们知道它只需要一个参数,可能是一个Action实例,因为我们看到1指示一个参数,然后5,如果解码为一个对象意味着我们读取第五个字符串(看看如何readObject用于查看原因).如果不知道哪些字段Action或其他类(下面列出),我们无法确切地猜测下一步会发生什么:
(请注意,我只是猜测这些是可序列化的类,它们的包和名称 - 它们可能只是简单的字符串,有人决定通过电线发送它们作为其请求的一部分!)
我们已经介绍了尝试拆分此消息的许多基础知识,所以让我们尝试将它组合在一起.管理它的GWT客户端代码中的类是com.google.gwt.user.client.rpc.impl.ClientSerializationStreamWriter.方法prepareToWrite()和toString()帮助设置了一点,展示了我们将围绕工作做的第一件也是最后一件事:
/**
* Call this method before attempting to append any tokens. This method
* implementation <b>must</b> be called by any overridden version.
*/
@Override
public void prepareToWrite() {
super.prepareToWrite();
encodeBuffer = new StringBuilder();
// Write serialization policy info
writeString(moduleBaseURL);
writeString(serializationPolicyStrongName);
}
@Override
public String toString() {
StringBuilder buffer = new StringBuilder();
writeHeader(buffer);
writeStringTable(buffer);
writePayload(buffer);
return buffer.toString();
}
Run Code Online (Sandbox Code Playgroud)
该prepareToWrite()方法从流中开始,添加两个字符串 - 模块基本URL和策略强名称,您将从反序列化过程中识别的字符串.该toString()方法显示了我们将要写出的三个阶段:标题,字符串表和"有效负载",或对象引用和原始值.
为什么我们将字符串与其他叶子值进行不同的跟踪?这样我们就可以在一个地方拥有所有字符串,这样我们可以多次引用它们,并且每次只发送它们.将此与XML或JSON进行对比,每次要使用值时,都必须再次写入值,即使它完全相同.
标题包含版本(最新版本为7),以及要设置的标志(在示例中,只需0).
在超类中AbstractSerializationStreamWriter,有四个字段:
private int objectCount;
private Map<Object, Integer> objectMap = new IdentityHashMap<Object, Integer>();
private Map<String, Integer> stringMap = new HashMap<String, Integer>();
private List<String> stringTable = new ArrayList<String>();
Run Code Online (Sandbox Code Playgroud)
第一个是每个对象的当前索引 - 我们将使用它来跟踪我们之前看到的对象.接下来objectMap,我们可以检查每个对象并检查我们之前是否已经看过它,如果是,那么在哪里,以便我们可以将引用写回到该位置.该stringMap字段做同样的事情,但对于字符串 - JS特别处理字符串键.最后,stringTable本身,我们看到的所有字符串的列表,每个只添加一次.
如果你为一个服务方法拆分已编译的应用程序生成的Java List<String> filterStrings(List<String> strings, String startsWith),你会看到如下所示:
ClientSerializationStreamWriter streamWriter = ...;//create with serializer
streamWriter.prepareToWrite();
streamWriter.writeString("com.acme.project.shared.MyService");//service interface
streamWriter.writeString("filterStrings");//method name
streamWriter.writeInt(2);//number of arguments to be found in the stream
streamWriter.writeObject(strings);
streamWriter.writeString(startsWith);
Run Code Online (Sandbox Code Playgroud)
确切地知道将为每种方法编写的内容取决于知道Java中的方法签名是什么 - 只需编译GWT JS和有效负载样本,逆向工程就有些困难了.但让我们继续,看看接下来会发生什么.
实现writeObject取对象并首先记录其类型.如果对象为null,那么我们只写一个空字符串(又名0)并完成.否则我们检查我们之前是否已经写过这个对象(因此写一个负数来查看有效载荷的去向),或者我们需要查找如何编写该对象的其余部分,并序列化每个字段.
每个可以序列化的对象都必须有一个FieldSerializer,它描述了如何编码和解码该对象.GWT中有许多CustomFieldSerializers,用于特定目的的自定义实现,它告诉RPC不自动生成序列化程序.一个例子可能是ArrayList,如果我们已经传递了 - ArrayList_CustomFieldSerializer委托给Collection_CustomFieldSerializerBase,这样做:
public static void serialize(SerializationStreamWriter streamWriter,
Collection instance) throws SerializationException {
int size = instance.size();
streamWriter.writeInt(size);
for (Object obj : instance) {
streamWriter.writeObject(obj);
}
}
Run Code Online (Sandbox Code Playgroud)
首先,我们编写列表的大小,以便反序列化器知道要读取多少元素,然后我们在列表中编写每个项目.在我们的例子中,我们将这些全部写为字符串.然后,我们将编写一个多字符串,第二个参数的方法.
所以,我们在String表中有这些数据:
strings和字符串startsWith,虽然因为我们不知道是否有重复,我们不知道是否会有相同数量的字符串.在我们的有效负载中,然后让我们说filterStrings(["a", "ab", "abc", "a"], "ab"),我们将有引用1(baseurl字符串索引),2(策略强名称字符串索引),3(服务名称字符串索引),4(方法名称字符串索引),2(int为期望的字段数),5(strings列表参数的类名),4(列表中的项目数),6(列表中第一项的类型,字符串),7("a"的内容), 6(字符串类型),8("ab"的内容),6(字符串类型),9("abc"的内容),6(字符串类型),7("a"的内容),6(字符串类型第二个参数),最后是8个("ab"的内容).
这会如何寻找像Action,DeclaracionJurada等类?我们不知道有哪些领域以及它们发生的顺序,我们不能肯定地说.从有效载荷中重建内容没有好办法,但是如果你可以在发送有效载荷之前调试运行的应用程序,你可以观察要序列化的对象的结构,并用它来决定你的内容发现在溪流中.我观察到样本流中有几个负数,表明负值对于用例很重要,或者有后引用,这不是一个简单的对象树,而是一个完整的图形,它会产生一些东西稍微复杂一点.
RPC序列化格式并不复杂 - 我强烈建议您阅读各个com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamReader子类中的代码以了解它的作用.从那里,您应该能够将这两个值列表(字符串和引用/基元)解析为实际对象,以及可能通过线路发送的所有类的结构,并以任何语言或框架重新实现它.
| 归档时间: |
|
| 查看次数: |
824 次 |
| 最近记录: |