Java使用HttpClient以multipart/form-data向接口上传文件

Posted 小源博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java使用HttpClient以multipart/form-data向接口上传文件相关的知识,希望对你有一定的参考价值。

前言

对接某公司的接口,涉及到资质上传等业务。需要对接他们的上传附件接口。
JDK1.8 httpclient 4.x

封装httpclient方法

public static String postFileMultiPart(String url,Map<String, ContentBody> reqParam) throws IOException
	CloseableHttpClient httpclient = HttpClients.createDefault();
	try 
		// 创建http
		HttpPost httppost = new HttpPost(url);
		//setConnectTimeout:设置连接超时时间,单位毫秒。setConnectionRequestTimeout:设置从connect Manager获取Connection 超时时间,单位毫秒。
		RequestConfig defaultRequestConfig = RequestConfig.custom().setConnectTimeout(5000).setConnectionRequestTimeout(5000).setSocketTimeout(15000).build();
		httppost.setConfig(defaultRequestConfig);
		MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
		for(Map.Entry<String,ContentBody> param : reqParam.entrySet())
			multipartEntityBuilder.addPart(param.getKey(), param.getValue());
		
		HttpEntity reqEntity = multipartEntityBuilder.build();
		httppost.setEntity(reqEntity);
		// 执行post请求.
		CloseableHttpResponse response = httpclient.execute(httppost);
		System.out.println("got response");
		try 
			// 获取响应实体
			HttpEntity entity = response.getEntity();
			if (entity != null) 
				return EntityUtils.toString(entity, Charset.forName("UTF-8"));
			
		 finally 
			response.close();
		
	 finally 
		// 关闭连接,释放资源
		try 
			httpclient.close();
		 catch (IOException e) 
			e.printStackTrace();
		
	
	return null;

因为我方系统需要给前端提供上传接口 使用的MultipartFile来接收文件
所以这边需要MultipartFile转下File文件

public static File transferToFile(MultipartFile multipartFile) 
	//选择用缓冲区来实现这个转换即使用java 创建的临时文件 使用 MultipartFile.transferto()方法 。
	File file = null;
	try 
		String originalFilename = multipartFile.getOriginalFilename();
		//获取文件后缀
		String prefix = originalFilename.substring(originalFilename.lastIndexOf("."));
		file = File.createTempFile(originalFilename, prefix);
		multipartFile.transferTo(file);
		//删除临时文件
		file.deleteOnExit();
	 catch (IOException e) 
		e.printStackTrace();
	
	return file;

方法调用

public RestResponse attachment(MultipartFile file) throws Exception 
	Map<String, ContentBody> reqParam = new HashMap<>();
	//普通类型
	reqParam.put("appId", new StringBody("appid", ContentType.MULTIPART_FORM_DATA));
	//文件
	reqParam.put("file", new FileBody(FileUploadUtils.transferToFile(file), ContentType.IMAGE_JPEG));
	String result = HttpClientUtil.postFileMultiPart("http://www.com/attachment", reqParam);

后记

一顿操作对接完事。肯定有朋友问 为什么不让前端兄弟直接对接呢。因为对接的接口有权限校验。前端直接调会有泄漏token和秘钥的风险。

HTTPClient 从 keytab 登录以访问 hadoop jobhistory 服务

【中文标题】HTTPClient 从 keytab 登录以访问 hadoop jobhistory 服务【英文标题】:HTTPClient login from keytab to access hadoop jobhistory service 【发布时间】:2015-09-20 19:51:46 【问题描述】:

我正在编写一个 java 程序来访问 hadoop jobhistory 服务以检索一些信息。

我正在使用 HTTPClient 进行 HttpGet 调用。我需要从 keytab 文件(我的 ~/.ssh/ 文件夹中有该文件)登录,而不是输入用户名和密码。

我的问题是:如何从 HTTPClient 中的 keytab 登录?

这是我设置 HTTPClient 的方式

System.setProperty("java.security.krb5.conf", "krb5.conf");
System.setProperty("sun.security.krb5.debug", "true");
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");

System.setProperty("java.security.krb5.realm", prop.getProperty("krb5.realm"));
System.setProperty("java.security.krb5.kdc", prop.getProperty("krb5.kdc"));

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(200);
cm.setDefaultMaxPerRoute(100);

//TODO login from keytab ?
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("DUMMY", null));

Lookup<AuthSchemeProvider> authRegistry = RegistryBuilder.<AuthSchemeProvider>create()
  .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
  .build();

httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider)
  .setDefaultAuthSchemeRegistry(authRegistry)
  .setConnectionManager(cm)
  .build();
HttpResponse response = httpClient.execute(request);

有趣的是,这段代码可以在我的 IntelliJ 中成功运行。但是在我从命令行构建并运行它之后,它会显示信息来询问我的用户名和密码。

我是身份验证的新手,希望有人能提供帮助。非常感谢。

【问题讨论】:

看看***.com/questions/21375372/… -- 在这种情况下不涉及 HTTP,但用于获取 Kerberos 票证的 GSSAPI 配置是相同的。并且该跟踪标志可以证明是有帮助的:***.com/questions/31824149/… 【参考方案1】:
    HttpClientBuilder builder = HttpClientBuilder.create();
    Lookup<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
            .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true)).build();
    builder.setDefaultAuthSchemeRegistry(authSchemeRegistry);
    BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(new AuthScope(null, -1, null), new Credentials() 
        @Override
        public Principal getUserPrincipal() 
            return null;
        

        @Override
        public String getPassword() 
            return null;
        
    );
    builder.setDefaultCredentialsProvider(credentialsProvider);
    final HttpClient httpClient = builder.build();

    final Subject subj = new Subject();
    Krb5LoginModule krb5 = new Krb5LoginModule();

    Map<String, String> options = new HashMap<>();
    options.put("doNotPrompt", "true");
    options.put("storeKey", "true");
    options.put("useKeyTab", "true");
    options.put("useTicketCache", "true");
    options.put("keyTab", keytabFilePath); //Path to keytab file
    options.put("principal", principal);   //Principal name
    options.put("debug", "true");

    krb5.initialize(subj, null, null, options);

    krb5.login();
    krb5.commit();

    HttpResponse response = Subject.doAs(subj, new PrivilegedExceptionAction<HttpResponse>() 
        @Override
        public HttpResponse run() throws Exception 
            return httpClient.execute(request);
        
    );

【讨论】:

添加一些细节可能对其他人有好处。 你是什么意思? 只是一堆代码,为你的代码添加一些原因/cmets。

以上是关于Java使用HttpClient以multipart/form-data向接口上传文件的主要内容,如果未能解决你的问题,请参考以下文章

HttpURLConnection与HttpClient浅析AAAA

释放 HttpClient 4.1.x 的连接以使用一个 HttpClient 实例顺序执行

如何在java中发送具有不同内容类型的mime multipart restful请求

我的多线程 HttpClient 有啥问题吗?

使用eclipse阅读java源码

java中HttpClient的使用