在Java中发布到HTTPS,奇怪的行为

bah*_*bah 8 php java curl

我决定用Java发布一些东西,但却陷入了这样一个看似微不足道的任务.然后我感到沮丧,并在PHP中重写整个事情,它完美无缺.我尝试比较Java和PHP结果的输出,以及我注意到Curl设置Content-Type:multipart/form-data; 而Java(正确吗?)将它设置为application/x-www-form-urlencoded; 但这会触发500内部服务器错误.这到底是怎么回事?

Java调试:

2017/12/11 19:10:36:236 EET [DEBUG] wire - http-outgoing-0 >> "POST /auth/register HTTP/1.1[\r][\n]"
2017/12/11 19:10:36:243 EET [DEBUG] wire - http-outgoing-0 >> "Cookie: XSRF-TOKEN=eyJpdiI6InJJRjdORWdzUVcwQVZMR2l2WnNHUWc9PSIsInZhbHVlIjoiZVFSc0V5MCtURFE4dTZHZGlwVXdna0VGMGZtNzh0aEF4eXJcL0ZcL3d6QWM4NVdJejJaeEptUDFcL0ZDeXBEOGlDMTltbEQ4cFg0c1wvK3h4Nkp3VEhJTmFRPT0iLCJtYWMiOiIzNmRjZGNmZGNmYTFkYTQzODQ2NjFkZWY3ZWVlZGJmNzBiNDFhNTQwNDU3ODAzMTA4MGNhYWRiY2VhNDU2ZmU2In0%3D;laravel_session=eyJpdiI6ImF3cGg2TUFvWm54b3J4Nml5NnlBYlE9PSIsInZhbHVlIjoiXC85ZzdJS2drRWxlWGExXC93bHFVNXRtTmFtTmcyblJ4cXY4eUhCY2toaWJGaFBcL2NjQllKekVrUWFvblhydWtSeHpySm4yWGlWbHE3Y3dXZjFxd3lXV3c9PSIsIm1hYyI6IjRlNGZiMjU4NDRmMWVjZjc1YzExYWM4ZjJlMTUyNzI0ZTY3NTAwYTUyZTdlNTdiZmQ2ZDg1NTk1OGE4OGQ3ZGMifQ%3D%3D[\r][\n]"
2017/12/11 19:10:36:243 EET [DEBUG] wire - http-outgoing-0 >> "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0[\r][\n]"
2017/12/11 19:10:36:243 EET [DEBUG] wire - http-outgoing-0 >> "Accept: */*[\r][\n]"
2017/12/11 19:10:36:243 EET [DEBUG] wire - http-outgoing-0 >> "Content-Length: 146[\r][\n]"
2017/12/11 19:10:36:243 EET [DEBUG] wire - http-outgoing-0 >> "Content-Type: application/x-www-form-urlencoded; charset=UTF-8[\r][\n]"
2017/12/11 19:10:36:243 EET [DEBUG] wire - http-outgoing-0 >> "Host: xxx[\r][\n]"
2017/12/11 19:10:36:243 EET [DEBUG] wire - http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
2017/12/11 19:10:36:243 EET [DEBUG] wire - http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
2017/12/11 19:10:36:243 EET [DEBUG] wire - http-outgoing-0 >> "[\r][\n]"
2017/12/11 19:10:36:244 EET [DEBUG] wire - http-outgoing-0 >> "username=jnfjkwejf&_token=ZTE8t5XDf2vmBcAWpSenELkEtqvhIp9FBSy0E1Ez&domain=xxx&password=qweqweqwe&password_confirmation=qweqweqwe&captcha=U8Aq3"
2017/12/11 19:10:36:319 EET [DEBUG] wire - http-outgoing-0 << "HTTP/1.1 500 Internal Server Error[\r][\n]"
Run Code Online (Sandbox Code Playgroud)

Java代码:

HttpHost target = new HttpHost("xxx", 443, "https");
        SSLContext sslcontext = SSLContexts.createSystemDefault();
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                sslcontext, new String[] { "TLSv1.2", "SSLv3" }, null,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());

        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", sslConnectionSocketFactory)
                .build();
    PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

    CloseableHttpClient httpsclient = HttpClients.custom()
            .setSSLSocketFactory(sslConnectionSocketFactory)
            .setConnectionManager(cm)
            .build();
    ArrayList<NameValuePair> formparams = new ArrayList<>();
    formparams.add(new BasicNameValuePair("username", "jnfjkwejf"));
    formparams.add(new BasicNameValuePair("_token", _token));
    formparams.add(new BasicNameValuePair("domain", "xxx"));
    formparams.add(new BasicNameValuePair("password", "qweqweqwe"));
    formparams.add(new BasicNameValuePair("password_confirmation", "qweqweqwe"));
    formparams.add(new BasicNameValuePair("captcha", captcha));
    UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, Consts.UTF_8);
    HttpPost httppost = new HttpPost("/auth/register");
    String fullCookie =
            captchaConn.getHeaderFields().get("Set-Cookie").get(1).split(";")[0] + ";" +
            captchaConn.getHeaderFields().get("Set-Cookie").get(0).split(";")[0];
    httppost.addHeader("Cookie", fullCookie);
    httppost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0");
    httppost.addHeader("Accept", "*/*");
    httppost.setEntity(entity);
    CloseableHttpResponse execute = httpsclient.execute(httppost);
Run Code Online (Sandbox Code Playgroud)

PHP:

> POST /auth/register HTTP/1.1
Host: xxx
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0
Accept: */*
Cookie: XSRF-TOKEN=eyJpdiI6Im4zSXNHanBpM1FmXC9oZ0dEeFZFbElRPT0iLCJ2YWx1ZSI6Inh2S2FKSktQMGFxREMwVU5KZHkzSVEzaXFyVnNWdEpiQ1IzVFd4Y3c3RWFxQXV6YXFRaFNuQlBSU2M5bEs5azh2dG9zSjFoQWlNVW00dGgzeW1IeFhRPT0iLCJtYWMiOiI4MTUwZTk3ZDNkZDMyOTkxMjRkNjRhY2I5MjEzMDZmNTk5NzUwYjA5NDY3YmY0OWQ4YzQ1NmMxNTVjZDIwNzNkIn0%3D; laravel_session=eyJpdiI6IldnbGd1STlUSVZXc0NFbWZLTVhGZEE9PSIsInZhbHVlIjoiRDBndzlSZFJLUlZHYWdJWmppZmNCOWRYV2liNnV1NFJkMzNoNEpyVGRBaXlEUm94MzNSbmZ4YVdDeHM0OTNNa21qZmQ1Tjd4UVJrK2pYS3BUQUhsbFE9PSIsIm1hYyI6ImZkNTBmZjYxOTc0ZmUxNzIzZTNlOTBkYWJmMzBkODhkODkxNTk1Mjc5Nzg5MTI5NmJkYzJlYzBjOTEyMGM0OTUifQ%3D%3D
Content-Length: 718
Expect: 100-continue
Content-Type: multipart/form-data; boundary=------------------------e939a893b45ae97c

< HTTP/1.1 100 Continue
< HTTP/1.1 302 Found
< Server: nginx/1.10.3
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Cache-Control: no-cache
...
Run Code Online (Sandbox Code Playgroud)

卷曲选项:

curl_setopt($ch, CURLOPT_URL, 'https://xxx/auth/register');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0');
curl_setopt($ch, CURLOPT_COOKIEFILE, __DIR__ . '.\cookiejar');
curl_setopt($ch, CURLOPT_COOKIEJAR, __DIR__ . '.\cookiejar');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
Run Code Online (Sandbox Code Playgroud)

vso*_*oni 5

如果您的服务器是期望的 Content-Type: multipart/form-data,那么您应该使用MultipartEntityBuilder而不是UrlEncodedFormEntity.

您的实体创建代码可能类似于

HttpEntity entity = MultipartEntityBuilder
    .create()
    .addTextBody("username", "jnfjkwejf")
    .addTextBody("_token", _token)
    .addTextBody("domain", "xxx")
    .addTextBody("password", "qweqweqwe")
    .addTextBody("password_confirmation", "qweqweqwe")
    .addTextBody("captcha", captcha)
    .build();
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅此链接.Apache HttpClient制作多部分表单帖子

更新 - 还有一点.

在Java情况下,您的cookie标头看起来不正确.cookie对应该用分号和空格('; ')分隔.你的java案例中缺少空格.参考 - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie


Fel*_*des 2

curl 可以使用这两种编码中的任何一种,就像 php 或 java 一样,只需正确配置请求类型即可。

urlencoded 是旧式的 multipart 是新的,java 必须能够生成两者,也许找到一个新的 java 示例?

另外,为什么不尝试自己构建实际的请求并通过自己逐字节创建请求来发送您需要发送的实际字节?将其视为一种学习练习。

为了调试服务器发送 500 错误的原因,我建议您阅读服务器的源代码并阅读服务器的日志,它可能只喜欢新的处理方式。

顺便说一句,我喜欢老方法,我喜欢简单。它曾经很简单,一个 POST 请求,在我那个时代......现在,新的方式,感觉很浪费,字节太多,数据太少。

  • 考虑使用 Apache 的 HTTPS 库 (2认同)