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文字を出力する場合と、CRLFペアを出力する場合があります。

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

すでにお気づきのとおり、2つの独立した問題が発生しています。Wiresharkが無効なチェックサムを表示していることと、サーバーがデータを正しく受信していないことです。

問題1:Wiresharkが無効なチェックサムを表示している

これはTCPチェックサムのオフロードが原因であることがすでにわかっていると思います。後世のために、私はあなたがすでに知っていることを繰り返します。

最近のコンピューターでは、OSは送信する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 に答える