0

我正在使用以下代码通过文件上传上传多表单/数据表单:

    URL url = new URL(DEST_URL);
    String boundary = "-----------------------------" + Long.toString(System.currentTimeMillis());
    PrintWriter writer = null;
    URLConnection con = url.openConnection();

    con.setDoInput(true);
    con.setDoOutput(true);
    con.setRequestProperty("Accept-Charset", "utf-8");
    con.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/json,application/xml;q=0.9,*/*;q=0.8");
    con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
    OutputStream output = con.getOutputStream();
    InputStream input = new FileInputStream(new File(FILE_PATH));
    writer = new PrintWriter(new OutputStreamWriter(output));

    writer.println(boundary);
    writer.println("Content-Disposition: form-data; name=\"input1\"");
    writer.println();
    writer.println("1234");

    writer.flush();

    writer.println(boundary);
    writer.println("Content-Disposition: form-data; name=\"input1\"");
    writer.println();
    writer.println("asdf");

    writer.flush();

    writer.println(boundary);
    writer.println("Content-Disposition: form-data; name=\"file1\"; filename=\"clicknpoint.png\"");
    writer.println("Content-Type: image/png");
    writer.println();

    writer.flush();

    int length = 0;
    byte[] buffer = new byte[1024];

    for(length = 0; (length = input.read(buffer)) > 0;) {
        output.write(buffer, 0, length);
    }
    writer.flush();
    input.close();

    writer.println();
    writer.println(boundary + "--");

    writer.flush();

    input = con.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(input));

    String cur = null;
    StringBuffer buf = new StringBuffer();

    while((cur = reader.readLine()) != null) {
        buf.append(cur);
    }

服务器无法识别请求中的参数。我用wireshark检查过,它们在那里,但IP头校验和是0x0000。我认为这是问题。

知道这是从哪里来的吗?

4

2 回答 2

1

我能看到的唯一可能不正确的是您使用 println 生成 HTTP 内容。根据您的平台,println 可能会输出单个 LF 字符,也可能会输出 CR LF 对。

HTTP 在每个标头之后肯定需要 CRLF。请参阅http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4。现在您的代码有违反 HTTP 协议的风险。它可能适用于某些平台,但不适用于其他平台。此外,一些服务器可能会容忍违反协议,但其他服务器可能不会。侵入性最小的更改可能是将每个 println 更改为打印并显式添加 CRLF。

writer.print("Content-Disposition: form-data; name=\"input1\"\r\n");

这可能与您的问题无关,但在您加强与 HTTP 的一致性之前,您的代码将面临失败的风险。

于 2012-10-17T14:43:20.680 回答
0

正如您已经意识到的那样,您正在查看两个独立的问题:Wireshark 显示无效校验和,并且您的服务器未正确接收数据。

问题 1:Wireshark 显示无效校验和

我意识到您已经发现这是因为 TCP 校验和卸载。为了后代,我将重复您已经知道的内容。

在现代计算机上,操作系统不会为它发出的每个 TCP 数据包计算校验和。相反,校验和是在网络适配器上的硬件中计算的。由于 Wireshark 会在数据包到达网络适配器之前对其进行拦截,因此它会看到错误的校验和。要确认卸载实际上是您在 Wireshark 中看到无效校验和的原因,您可以暂时将其关闭。对于 Mac OS X,在终端中使用以下命令:

sudo sysctl -w net.link.ether.inet.apple_hwcksum_tx=0
sudo sysctl -w net.link.ether.inet.apple_hwcksum_rx=0

要在测试后重新启用,只需将那些 0 替换为 1。要在其他操作系统上禁用卸载,请参见步骤 3部分。如果可能,禁用 TCP 和 UDP 校验和卸载以及 TCP 分段卸载

问题 2:服务器未正确接收数据

URLConnection 对象不可重用。在 URLConnection 的输出流上调用 flush() 或 write() 会立即发送您的请求。之后,您必须创建一个新的 URLConnection。在调用这些方法中的任何一个之前,请确保您的所有数据都已添加到输出流中。关于操纵 URLConnections 的 I/O 流的后果的一个非常好的讨论可以在这里找到: http ://www.javaworld.com/javaworld/jw-03-2001/jw-0323-traps.html?page=4

于 2013-09-06T08:51:43.480 回答