简体   繁体   English

使用Apache HttpClient的多部分表单数据发布不起作用

[英]Multipart form-data posting using Apache HttpClient not working

I'm trying to post to my website using a java desktop application. 我正在尝试使用Java桌面应用程序发布到我的网站。 I used Apache HttpClient to make the post request and Jsoup to do some parsing after. 我使用Apache HttpClient发出发布请求,然后使用Jsoup进行一些解析。

This is the form on my website: 这是我网站上的表格:

<form name="item" action="http://example.com/index.php" method="post" enctype="multipart/form-data">
   <input type="hidden" name="CSRFName" value="CSRF1142289289_807321318">
   <input type="hidden" name="CSRFToken" value="2db57fc741cdb8c1b02a2f485508def7796162f5eebdd9f7d0ce9fd9aabb39ecd5df8c63a46560ae540ed9f26c40fdd33f0285e7b1f2ef18bc4b760ad3da4ae8">
   <fieldset>
      <input type="hidden" name="action" value="item_add_post">
      <input type="hidden" name="page" value="item">
      <input id="catId" type="hidden" name="catId" value="">
      <select id="select_1" name="select_1" depth="1" class="valid">
         <option value="0">Selectează categoria</option>
         <option value="108">Cazare si Pensiuni</option>
         <option value="105">Transport si Turism</option>
      </select>
      <input id="titlero_RO" type="text" name="title[ro_RO]" value="">
      <textarea id="descriptionro_RO" name="description[ro_RO]" rows="10" class="uniform"></textarea>
      <input id="price" type="text" name="price" value="">           
      <select name="currency" id="currency">
      <option value="EUR">euro</option>
         <option value="RON" selected="selected">lei</option>
         <option value="USD">dollar</option>
      </select>
      <input type="file" name="photos[]"><span class="filename" style="-webkit-user-select: none;">
      <select name="regionId" id="regionId">
         <option value="">Regiunea</option>
         <option value="782153">Alba</option>
      </select>
      <select name="cityId" id="cityId" disabled="disabled">
         <option value="">Orasul</option>
         <option value="462667">Abrud</option>
      </select>
      <input id="cityArea" type="text" name="cityArea" value="">
      <input id="cityAreaId" type="hidden" name="cityAreaId" value="">
      <input id="contactName" type="text" name="contactName" value="">                       
      <input id="contactEmail" type="text" name="contactEmail" value="">            
      <div class="button" style="-webkit-user-select: none;"><span>Publică<button type="submit">Publică</button></span></div>
   </fieldset>
</form>

Of course i've removed some stuff from it such as divs, css for this, I kept the minimum. 当然,我已经从中删除了一些东西,例如divs,css,我保持了最低限度。

If I submit the form through my browser the actual data sent is this one: 如果我通过浏览器提交表单,则发送的实际数据就是:

Remote Address:xx.xxx.xx.xxx:80
Request URL:http://example.com.ro/index.php
Request Method:POST
Status Code:302 Moved Temporarily
Request Headersview source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,lzma,sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Content-Length:2398
Content-Type:multipart/form-data; boundary=----WebKitFormBoundarybWBRwGAP2qS2vOYX
Cookie:_ugtopperm=1; b620f=last_submit_item%261406384018; _ugtopsecure=1;         osclass=f8e8a642a5d853ef3ca332a44604b975
Host:example.com.ro
Origin:http://example.com.ro
Referer:http://example.com.ro/adauga
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)     Chrome/36.0.1985.125 Safari/537.36 OPR/23.0.1522.60
Request Payload
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="CSRFName"

CSRF1142289289_807321318
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="CSRFToken"

2db57fc741cdb8c1b02a2f485508def7796162f5eebdd9f7d0ce9fd9aabb39ecd5df8c63a46560ae540ed9f26c40fdd33f0285e7b1f2ef18bc4b760ad3da4ae8
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="action"

item_add_post
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="page"

item
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="catId"

98
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="select_1"

98
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="title[ro_RO]"

This is the ad title
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="description[ro_RO]"

This is the ad description lots of text etc...
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="price"

5
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="currency"

RON
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="photos[]"; filename=""
Content-Type: application/octet-stream


------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="regionId"

782162
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="cityId"

463357
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="cityArea"

0123457617
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="cityAreaId"


------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="contactName"

nic
------WebKitFormBoundarybWBRwGAP2qS2vOYX
Content-Disposition: form-data; name="contactEmail"

nicolae_aldea@yahoo.com
------WebKitFormBoundarybWBRwGAP2qS2vOYX--
Response Headersview source
Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection:Keep-Alive
Content-Length:0
Content-Type:text/html
Date:Wed, 30 Jul 2014 13:41:38 GMT
Expires:Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive:timeout=3, max=100
Location:http://example.com.ro/prestari-servicii
Pragma:no-cache
Server:Apache/2.2.27 (Unix) mod_ssl/2.2.27 OpenSSL/0.9.8e-fips-rhel5 mod_bwlimited/1.4
Set-Cookie:b620f=last_submit_item%261406727698; expires=Thu, 30-Jul-2015 13:41:38 GMT;     path=/
X-Powered-By:PHP/5.3.28

And it works ok. 而且行得通。 After I click the Publish button (in the browser) I get redirected from /adauga to /prestari-servicii where I can see that ad I just typed. 单击发布按钮(在浏览器中)后,我从/ adauga重定向到/ prestari-servicii,在其中可以看到我刚刚键入的广告。

Now I tried to mimic the same thing in java using Apache HttpClient 现在,我尝试使用Apache HttpClient模仿Java中的同一件事

package abcd;

import java.io.File;
import java.util.List;
import java.util.Random;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

public class Test {
    public static void main(String[] args) throws Exception {
        BasicCookieStore cookieStore = new BasicCookieStore();
        CloseableHttpClient client = HttpClients.custom()
            .setDefaultCookieStore(cookieStore).build();

        //trying to get the cookies if any?!
        HttpGet get = new HttpGet("http://example.com.ro/adauga");
        get.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        get.setHeader("Accept-Encoding", "gzip,deflate,lzma,sdch");
        get.setHeader("Accept-Language", "en-US,en;q=0.8");
        get.setHeader("Cache-Control", "max-age=0");
        get.setHeader("Connection", "keep-alive");
    /* HERE IS THE PART I THINK IT MESSES UP
        get.setHeader("Cookies", what should i set here? is the job done by client
    having the cookieStore set?? 
    */
        get.setHeader("Host", "example.com.ro");
        get.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36 OPR/23.0.1522.60");
        CloseableHttpResponse response1 = client.execute(get);

        List<Cookie> cookies = cookieStore.getCookies();
        if (cookies.isEmpty()) {
            System.out.println("None");
        } else {
            for (int i = 0; i < cookies.size(); i++) {
                System.out.println("- " + cookies.get(i).toString());
            }
        }

        response1.close();

        //my site uses CSRF protection in the form so first I take these using Jsoup
        Document html = Jsoup.connect("http://example.com.ro/adauga").get();
        String CSRFName = html.getElementsByAttributeValue("name", "CSRFName").get(0).val();
        String CSRFToken = html.getElementsByAttributeValue("name", "CSRFToken").get(0).val();

        File image = new File("C:\\Users\\DESKTOP\\Desktop\\Capture.PNG");
        FileBody photos = new FileBody(image, ContentType.APPLICATION_OCTET_STREAM);

        StringBody csrfName = new StringBody(CSRFName, ContentType.MULTIPART_FORM_DATA);
        StringBody csrfToken = new StringBody(CSRFToken, ContentType.MULTIPART_FORM_DATA);
        StringBody action = new StringBody("item_add_post", ContentType.MULTIPART_FORM_DATA);
        StringBody page = new StringBody("item", ContentType.MULTIPART_FORM_DATA);
        StringBody catId = new StringBody("98", ContentType.MULTIPART_FORM_DATA);
        StringBody select_1 = new StringBody("98", ContentType.MULTIPART_FORM_DATA);
        StringBody title = new StringBody("Sample title text etc", ContentType.MULTIPART_FORM_DATA);
        StringBody description = new StringBody("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.", ContentType.MULTIPART_FORM_DATA);
        StringBody price = new StringBody("2", ContentType.MULTIPART_FORM_DATA);
        StringBody currency = new StringBody("RON", ContentType.MULTIPART_FORM_DATA);
        StringBody regionId = new StringBody("782162", ContentType.MULTIPART_FORM_DATA);
        StringBody cityId = new StringBody("463357", ContentType.MULTIPART_FORM_DATA);
        StringBody cityArea = new StringBody("0123577617", ContentType.MULTIPART_FORM_DATA);
        StringBody cityAreaId = new StringBody("", ContentType.MULTIPART_FORM_DATA);
        StringBody contactName = new StringBody("Garry", ContentType.MULTIPART_FORM_DATA);
        StringBody contactEmail = new StringBody("bogus@email.abc", ContentType.MULTIPART_FORM_DATA);

        HttpPost post = new HttpPost("http://example.com.ro/index.php");
        post.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        post.setHeader("Accept-Encoding", "gzip,deflate,lzma,sdch");
        post.setHeader("Accept-Language", "en-US,en;q=0.8");
        post.setHeader("Cache-Control", "max-age=0");
        post.setHeader("Connection", "keep-alive");
        post.setHeader("Content-Type", "multipart/form-data");
    //again, I think i'm doing something wrong here. Am I supposed to set
    //boundary as this??
        post.setHeader("boundary", generateBoundary());
    //should i set cookies after? if so, how?!
        post.setHeader("Host", "example.com.ro");
        post.setHeader("Origin", "http://example.com.ro");
        post.setHeader("Referer", "http://example.com.ro/adauga");
        post.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36 OPR/23.0.1522.60");

        HttpEntity entity = MultipartEntityBuilder.create()
                .addPart("CSRFName", csrfName)
                .addPart("CSRFToken", csrfToken)
                .addPart("action", action)
                .addPart("page", page)
                .addPart("catId", catId)
                .addPart("select_1", select_1)
                .addPart("title[ro_RO]", title)
                .addPart("description[ro_RO]", description)
                .addPart("price", price)
                .addPart("currency", currency)
                .addPart("photos[]", photos)
                .addPart("regionId", regionId)
                .addPart("cityId", cityId)
                .addPart("cityArea", cityArea)
                .addPart("cityAreaId", cityAreaId)
                .addPart("contactName", contactName)
                .addPart("contactEmail", contactEmail)
                .build();


        post.setEntity(entity);


        CloseableHttpResponse response = client.execute(post);
        System.out.println("After executing the post request... :" + response.getStatusLine().getStatusCode() + " - " + response.getStatusLine());

        String htmlPageResponse = EntityUtils.toString(response.getEntity());
        System.out.println();
        System.out.println(htmlPageResponse);
        response.close();
        client.close();
    }

    protected static String generateBoundary() {
        StringBuilder buffer = new StringBuilder();
        Random rand = new Random();
        int count = rand.nextInt(11) + 30; // a random size from 30 to 40
        for (int i = 0; i < count; i++) {
        buffer.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]);
        }
        return buffer.toString();
   }

    private final static char[] MULTIPART_CHARS =
        "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
         .toCharArray();
}

After I run this I get 200 - HTTP/1.1 200 OK Instead of 302 as I get when I use the browser. 运行此命令后,我得到200-HTTP / 1.1 200 OK,而不是使用浏览器时的302。 I also checked the html response and it was the original index.php page instead of the redirect where I was supposed to view my just entered message. 我还检查了html响应,它是原始的index.php页面,而不是应该查看我刚刚输入的消息的重定向。

So did I set the cookies right? 那我把饼干设置好了吗? Or I messed something in the request headers? 还是我在请求标头中弄乱了东西? Like the boundary etc. I had this problem for a week almost. 像边界等一样,我几乎一个星期都遇到了这个问题。 I tried every single httpclient multipart example but they don't seem to work with a "real world" website. 我尝试了每个单独的httpclient多部分示例,但它们似乎不适用于“现实世界”网站。

Thank you! 谢谢!

Have you tried to compare the request you created using Apache HttpClient with the one you posted above? 您是否尝试过将使用Apache HttpClient创建的请求与上面发布的请求进行比较? Doing so, you could easily check if the two are really the same, and whether you did something wrong or not in setting the cookies. 这样做,您可以轻松地检查两者是否真的相同,以及在设置Cookie时是否做错了什么。

To view the request before executing it you can print it before executing it. 要在执行之前查看请求,可以在执行之前将其打印。 Try System.out.println(get.toString()); 试试System.out.println(get.toString()); or alternatively, you can use HttpMessage's method - getFirstHeader("cookie") to look into the Header you set. 或者,您可以使用HttpMessage的方法-getFirstHeader getFirstHeader("cookie")来查看设置的Header。

But in order to mimic the actual request, I guess you should create a Cookie object and then use methods from SetCookie Interface to set it accordingly to Cookie:_ugtopperm=1; b620f=last_submit_item%261406384018; _ugtopsecure=1; 但是为了模仿实际的请求,我想您应该创建一个Cookie对象,然后使用SetCookie接口中的方法将其相应地设置为Cookie:_ugtopperm=1; b620f=last_submit_item%261406384018; _ugtopsecure=1; Cookie:_ugtopperm=1; b620f=last_submit_item%261406384018; _ugtopsecure=1; . At that point, you can use cookieStore.addCookie(Cookie cookie) method just after BasicCookieStore cookieStore = new BasicCookieStore(); 那时,您可以在BasicCookieStore cookieStore = new BasicCookieStore();之后使用cookieStore.addCookie(Cookie cookie)方法BasicCookieStore cookieStore = new BasicCookieStore();

I haven't never done this myself. 我从来没有自己做过。 But this is what I understood by taking a look to the APIs. 但这是我通过了解API所了解的。 I hope this might be of some help. 我希望这会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM