Web开发 之HttpClient详解

Web API 哪家强?Axios、Fetch 和 HttpClient 优选指南 在 Fetch、Axios 和 Angular HttpClient 之间该如何选择取决于我们具体的项目要求:Fetch API:JavaScript 原生,无其他依赖项,需手动错误处理。Axios:语法更简单,内置错误处理,具有请求取消和拦截器等附加功能。Angular HttpClient:集成 Angular,具有强大的 TypeScript 支持,结构化的错误处理。总而言之,对于比较简单的项目,或者关键是最少化依赖项时,选择Fetch API 恰到好处。 阅读详情

参考网址

HttpClient中文官网
HttpClient Apache官方文档
HttpClient 4.3教程
一个非常好的HttpClient系列教程

Maven依赖

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.10</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.62</version>
</dependency>

HttpClient模拟post请求示例

使用HttpClient发送请求、接收响应一般步骤:

  • 创建HttpClient对象。
  • 创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
  • 如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HttpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。
  • 调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。
  • 调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
  • 释放连接。无论执行方法是否成功,都必须释放连接。
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class SimpleHttpClientDemo {
    /**
     * 模拟请求
     *
     * @param url      资源地址
     * @param map      参数列表
     * @param encoding 编码
     * @return
     * @throws ParseException
     * @throws IOException
     */
    public static String send(String url, Map<String, String> map, String encoding) throws ParseException, IOException {
        String body = "";

        //创建httpclient对象
        CloseableHttpClient client = HttpClients.createDefault();
        //创建post方式请求对象
        HttpPost httpPost = new HttpPost(url);

        //装填参数
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        if (map != null) {
            for (Map.Entry<String, String> entry : map.entrySet()) {
                nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }
        //设置参数到请求对象中
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding));

        System.out.println("请求地址:" + url);
        System.out.println("请求参数:" + nvps.toString());

        //设置header信息
        //指定报文头【Content-type】、【User-Agent】
        httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
        httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

        //执行请求操作,并拿到结果(同步阻塞)
        CloseableHttpResponse response = client.execute(httpPost);
        //获取结果实体
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            //按指定编码转换结果实体为String类型
            body = EntityUtils.toString(entity, encoding);
        }
        EntityUtils.consume(entity);
        //释放链接
        response.close();
        return body;
    }

}

HttpClient连接池

HttpClient连接池设置引发的一次雪崩
httpclient连接池的测试报告(jmeter做并发测试工具)
HttpClient高并发下性能优化
HttpClient连接池的一些思考
httpclient连接池是否能真的提高性能
Http持久连接与HttpClient连接池
HttpClient连接池配置

PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager();
// 设置连接池的最大连接数
pool.setMaxTotal(200);
// 设置每个路由的最大连接数,路由是对MaxTotal的细分
pool.setDefaultMaxPerRoute(10);
// 在从连接池获取连接时,连接不活跃多长时间后需要进行一次验证,默认2s
pool.setValidateAfterInactivity(5*1000);
// 单独为某个站点设置最大连接个数
pool.setMaxPerRoute(new HttpRoute(new HttpHost("127.0.0.1", 80)), 50);
//默认请求配置
RequestConfig requestConfig = RequestConfig.custom()
        .setConnectTimeout(2*1000)// 设置连接超时时间 2s
        .setSocketTimeout(5*1000)// 设置等待数据超时时间 5s
        .setConnectionRequestTimeout(2000)// 设置从连接池获取连接的等待超时时间
        .build();
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(pool)
                .evictIdleConnections(1, TimeUnit.MINUTES) //定期回收空闲连接
                .setDefaultRequestConfig(requestConfig) // 设置默认请求配置
                .evictExpiredConnections()//定期回收过期连接
                .build();

为什么要用Http连接池

1、降低延迟:如果不采用连接池,每次连接发起Http请求的时候都会重新建立TCP连接(经历3次握手),用完就会关闭连接(4次挥手),如果采用连接池则减少了这部分时间损耗。

2、支持更大的并发:如果不采用连接池,每次连接都会打开一个端口,在大并发的情况下系统的端口资源很快就会被用完,导致无法建立新的连接。
如短连接去做压测,可能会报错:java.net.NoRouteToHostException: Cannot assign requested address。

而我们一般用的长连接是通过添加Keep-Alive头参解决: header.add(new NVPair(“Connection”, “Keep-Alive”));

而事实上头参中加了此参数只是保持长连接,与建立TCP连接保持的长连接不一样。

HttpClient connecttimeout与sockettimeout区别

HttpClient 作为 Http 工具包,是基于socket的封装,所以 HttpClient 的connectTimeout、socketTimeout其实都是socket的connectTimeout、socketTimeout。

connectTimeout: 建立链接的最大时间,也就是完成三次握手,建立TCP链接所用的时间。
socketTimeout: InputStream上调用read()方法阻塞的最大时间,即等待数据的时间或者两个包之间的间隔时间。

  • 程序中最好设置connectTimeout、socketTimeout,可以防止阻塞
    • 如果不设置connectTimeout会导致,建立TCP链接时,阻塞,假死。
    • 如果不设置socketTimeout会导致,已经建立了TCP链接,在通信时,发送了请求报文,恰好此时,网络断掉,程序就阻塞,假死在那。
  • 有时,connectTimeout并不像你想的那样一直到最大时间
    • socket建立链接时,如果网络层确定不可达,会直接抛出异常,不会一直到connectTimeout的设定值。
    • socket连接一个不存在的ip,很快就会提示连不上,而不是等到指定时间才报错。推测可能底层网络已经确定目标不可达所以不会一直重试直到connecttimeout。

HttpClient重试

关于HttpClient重试策略的研究

提供两种重试机制:

  • HttpRequestRetryHandler:针对异常的重试(例如:connect timed out、read timed out)
  • ServiceUnavailableRetryStrategy:针对响应错误码的重试(例如:400、500等)

HttpRequestRetryHandler

HttpClient提供针对异常重试的接口,实现该接口就可以编写异常重试方案。

DefaultHttpRequestRetryHandler

HttpClient提供的默认重试方案。

StandardHttpRequestRetryHandler

这是官方提供的一个标准的retry方案,为了保证幂等性约定Resetful接口必须是GET, HEAD, PUT, DELETE, OPTIONS, and TRACE中的一种。
在这里插入图片描述

自定义重试

实现 HttpRequestRetryHandler 接口,在 retryRequest 方法中编写重试逻辑。

public static CloseableHttpClient getHttpClient() {
    HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
        // exception:异常,executionCount:重试次数
        // 返回true表示重试,返回false表示不需要重试
        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
            System.out.println("重试第" + executionCount + "次");
            if (executionCount >= 3) {
                // Do not retry if over max retry count
                return false;
            }
            if (exception instanceof InterruptedIOException) {
                // Timeout
                return false;
            }
            if (exception instanceof UnknownHostException) {
                // Unknown host
                return false;
            }
            if (exception instanceof ConnectTimeoutException) {
                // Connection refused
                return false;
            }
            if (exception instanceof SSLException) {
                // SSL handshake exception
                return false;
            }
            HttpClientContext clientContext = HttpClientContext.adapt(context);
            HttpRequest request = clientContext.getRequest();
            boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
            if (idempotent) {
                // 如果请求被认为是幂等的,那么就重试
                return true;
            }
            return false;
        }
    };
    return HttpClients.custom().setRetryHandler(httpRequestRetryHandler)
            .setConnectionManager(new PoolingHttpClientConnectionManager()).build();
}

ServiceUnavailableRetryStrategy

针对响应错误码的重试,并且可以自定义重试时间的间隔。


public class MyServiceUnavailableRetryStrategy implements ServiceUnavailableRetryStrategy {
    private int executionCount;
    private long retryInterval;
    MyServiceUnavailableRetryStrategy(Builder builder) {
        this.executionCount = builder.executionCount;
        this.retryInterval = builder.retryInterval;
    }
    // retry逻辑
    @Override
    public boolean retryRequest(HttpResponse response, int executionCount, HttpContext context) {
        if (response.getStatusLine().getStatusCode() != 200 && executionCount < this.executionCount){
            // 表示错误码不是200并且小于最大重试次数进行重试
            return true;
        }
        else{
            return false;
        }
    }
    // retry间隔时间
    @Override
    public long getRetryInterval() {
        return this.retryInterval;
    }
    public static final class Builder {
        private int executionCount;
        private long retryInterval;
        public Builder() {
            executionCount = 3;
            retryInterval = 1000;
        }
        public Builder executionCount(int executionCount) {
            this.executionCount = executionCount;
            return this;
        }
        public Builder retryInterval(long retryInterval) {
            this.retryInterval = retryInterval;
            return this;
        }
        public MyServiceUnavailableRetryStrategy build() {
            return new MyServiceUnavailableRetryStrategy(this);
        }
    }
}
public static CloseableHttpClient getHttpClient() {
    ServiceUnavailableRetryStrategy serviceUnavailableRetryStrategy = new MyServiceUnavailableRetryStrategy.Builder()
            .executionCount(3)
            .retryInterval(1000)
            .build();
    return HttpClients.custom().setServiceUnavailableRetryStrategy(serviceUnavailableRetryStrategy)
            .setConnectionManager(new PoolingHttpClientConnectionManager()).build();
}

HttpClient封装

HttpClient用法–这一篇全了解(内含例子)
HttpClient详细使用示例

httpclient.properties 配置:

http.maxTotal=200
http.defaultMaxPerRoute=50
http.connectTimeout=2000
http.connectionRequestTimeout=500
http.socketTimeout=10000
http.staleConnectionCheckEnabled=true

Bean配置类:

import lombok.Getter;
import lombok.Setter;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import java.util.concurrent.TimeUnit;

@Configuration
@PropertySource(value = "classpath:httpclient.properties")
@Getter
@Setter
public class HttpClientConfig {
    @Value("${http.maxTotal}")
    private int maxTotal;
    @Value("${http.defaultMaxPerRoute}")
    private int defaultMaxPerRoute;
    @Value("${http.connectTimeout}")
    private int connectTimeout;
    @Value("${http.connectionRequestTimeout}")
    private int connectionRequestTimeout;
    @Value("${http.socketTimeout}")
    private int socketTimeout;
    @Value("${http.staleConnectionCheckEnabled}")
    private boolean staleConnectionCheckEnabled;

    @Bean
    public CloseableHttpClient httpClient(){
        PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager();
        // 设置连接池的最大连接数
        pool.setMaxTotal(maxTotal);
        // 设置每个路由的最大连接数,路由是对MaxTotal的细分
        pool.setDefaultMaxPerRoute(defaultMaxPerRoute);
        return HttpClients.custom().setConnectionManager(pool)
                // 定期回收空闲连接
                .evictIdleConnections(1, TimeUnit.MINUTES)
                // 定期回收过期连接
                .evictExpiredConnections()
                .build();
    }

    @Bean
    public RequestConfig requestConfig(){
        return RequestConfig.custom()
                // 设置连接超时时间
                .setConnectTimeout(connectTimeout)
                // 设置等待数据超时时间
                .setSocketTimeout(socketTimeout)
                // 设置从连接池获取连接的等待超时时间
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .build();
    }
}

Http响应结果类:

public class HttpResult {
    private Integer status;
    private String content;
    public HttpResult(){}

    public HttpResult(Integer status, String content) {
        this.status = status;
        this.content = content;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

Http请求封装类:

import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class HttpClientUtil {

    @Autowired(required = false)
    private CloseableHttpClient httpClient;

    @Autowired(required = false)
    private RequestConfig requestConfig;

    /**
     * 执行GET请求,如果请求状态不为200返回null
     *
     * @param url
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public String doGet(String url) throws ClientProtocolException, IOException {
        // 创建http GET请求
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(requestConfig);

        CloseableHttpResponse response = null;
        try {
            // 执行请求
            response = httpClient.execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                return EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return null;
    }

    /**
     * 带参数的GET请求
     *
     * @param url
     * @param params
     * @return
     * @throws URISyntaxException
     * @throws ClientProtocolException
     * @throws IOException
     */
    public String doGet(String url, Map<String, Object> params) throws URISyntaxException,
            ClientProtocolException, IOException {
        // 拼接URL
        URIBuilder uriBuilder = new URIBuilder(url);
        if (null != params) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                uriBuilder.setParameter(entry.getKey(), entry.getValue().toString());
            }
        }
        String newUrl = uriBuilder.build().toString();
        return doGet(newUrl);
    }

    /**
     * 执行doPOST请求,请求响应状态不为200返回null
     *
     * @param url
     * @param params
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public HttpResult doPost(String url, Map<String, Object> params) throws ClientProtocolException,
            IOException {
        // 创建http POST请求
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        setFormEntity(httpPost, params);
        return doHttp(httpPost);
    }

    /**
     * post提交json
     *
     * @param url
     * @param json
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public HttpResult doPostJson(String url, String json) throws ClientProtocolException, IOException {
        // 创建http POST请求
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        // 设置参数
        if (null != json) {
            // 构造一个form表单式的实体
            StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON);
            // 将请求实体设置到httpPost对象中
            httpPost.setEntity(stringEntity);
        }

        return doHttp(httpPost);
    }

    /**
     * 执行POST请求
     *
     * @param url
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public HttpResult doPost(String url) throws ClientProtocolException, IOException {
        return doPost(url, null);
    }

    /**
     * 执行doPut请求,请求响应状态不为200返回null
     *
     * @param url
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public HttpResult doPut(String url) throws ClientProtocolException, IOException {
        return doPut(url, null);
    }

    /**
     * 执行doPut请求,请求响应状态不为200返回null
     *
     * @param url
     * @param params
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public HttpResult doPut(String url, Map<String, Object> params) throws ClientProtocolException,
            IOException {
        // 创建http PUT请求
        HttpPut httpPut = new HttpPut(url);
        httpPut.setConfig(requestConfig);
        setFormEntity(httpPut, params);
        return doHttp(httpPut);
    }

    /**
     * 执行DELETE请求
     *
     * @param url
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public HttpResult doDelete(String url) throws ClientProtocolException, IOException {
        // 创建http PUT请求
        HttpDelete httpDelete = new HttpDelete(url);
        httpDelete.setConfig(requestConfig);
        return doHttp(httpDelete);
    }

    /**
     * 执行DELETE请求,使用_method指定DELETE请求,实际发送的POST请求
     *
     * @param url
     * @param params
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public HttpResult doDelete(String url, Map<String, Object> params) throws ClientProtocolException,
            IOException {
        if (params == null) {
            params = new HashMap<String, Object>();
        }
        params.put("_method", "DELETE");
        return doPost(url, params);
    }

    private void setFormEntity(HttpEntityEnclosingRequestBase requestBase, Map<String, Object> params)
            throws UnsupportedEncodingException {
        // 设置参数
        if (null != params) {
            // 参数列表
            List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
            }
            // 构造一个form表单式的实体
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
            // 将请求实体设置到httpPost对象中
            requestBase.setEntity(formEntity);
        }
    }

    private HttpResult doHttp(HttpRequestBase requestBase) throws ClientProtocolException, IOException {
        CloseableHttpResponse response = null;
        try {
            // 执行请求
            response = httpClient.execute(requestBase);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                return new HttpResult(200, EntityUtils.toString(response.getEntity(), "UTF-8"));
            } else {
                return new HttpResult(response.getStatusLine().getStatusCode(), null);
            }
        } finally {
            if (response != null) {
                response.close();
            }
        }
    }

}
使用 Java 11 的 HttpClient 处理 RESTful Web 服务 HttpClient是 Java 11 引入的标准 API,用于发送 HTTP 请求和接收响应。协议支持:兼容 HTTP/1.1 和 HTTP/2,HTTP/2 提供头部压缩和多路复用等性能优化。同步和异步:支持阻塞(同步)和非阻塞(异步)请求,适合不同应用场景。构建器模式:使用流畅的构建器模式配置客户端和请求。响应处理:通过提供多种方式处理响应体,如字符串、字节数组或文件。其他功能:支持重定向、代理、认证和 WebSocket。与旧的。 阅读详情

相关推荐

HttpClient实现原理深度解析

在当今互联网时代,网络通信已经成为各种应用程序不可或缺的一部分。而HttpClient作为一个强大的网络通信库,在现代网络编程中扮演着至关重要的角色。本文旨在深度解析HttpClient的实现原理,以帮助读者更好地理解其工作机制,从而提升网络编程能力。

fudaihb的博客 1500

HttpClient详解

参考 HTTP2.0关于多路复用的研究 HttpClient 官网 1. 背景 HTTP协议可以说是用的非常多的一种协议,Web、APP等都离不开Http协议,所以掌握Http协议非常有必要。 1.1 Http无状态 无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。从...

chijiang6541的博客 452

ESP8266开发之旅 网络篇⑨ HttpClient——ESP8266HTTPClient库的使用

1. 前言     在前面章节的博客中,博主介绍了ESP8266WiFi库 Tcp client的用法,并模拟了Http请求。但是,可以看出通过WiFiClient模拟Http请求,我们需要自己拼装Http请求协议,稍微不小心就很容易拼接错误。     那么有没有针对Http请求操作的库呢?答案肯定是有的,这就是博主本篇需要跟大家讲述的知识——ESP8266HTTPClient库。     请注意...

单片机菜鸟哥的博客 3万+

HttpClient使用详解

文章目录1 HttpClient1.1 简介1.2 HttpClient特性1.3 使用方法1.4 实例1.4.1 HttpClient连接SSL1.4.2 POST提交1.4.3 GET请求1.4.4 上传文件 1 HttpClient 1.1 简介 HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。HttpClient已经应用在很多的项目中 HttpClient相比传统

上善若泪 3632

Apache Commons HttpClient 3.1安卓开发实战详解

Apache HttpClient 3.1 是 Java 平台早期最广泛使用的 HTTP 客户端库之一,作为 Jakarta Commons 项目的重要组成部分,它为开发者提供了简洁、灵活且可扩展的编程接口,用于实现 HTTP/1.1 协议的客户端通信。该版本发布于2007年,正值 Web 服务快速发展的时代,其设计目标是替代 JDK 原生 URLConnection 的复杂性和局限性,提供更高级别的抽象和更强的控制能力。

weixin_42611310的博客 686

IAP板卡远程升级(串口网口都可)+Ymodem+AES对bin文件加密+pc软件+板卡相互烧录

还是决定记录一下,毕竟这个东西我也搞了挺久的,遇到一些棘手的,或者是因为我很粗心遇到的问题也和大家分享一下,。 板卡核心是 STM32F103RCT6,256kflash 前言 开始看这个远程升级的时候,我是一头雾水的,原子哥的教程里面也有说到过iap,有了一个大概的了解,我想不明白的是,通过串口下载的方式把hex文件下载到flash,和把bin文件下载到flash难道不是拉一根线,下载一个文件嘛,(初入职场的我并没有考虑到安全这个问题)如果直接将hex文件给到客户那边,风险是非常大...

那可真是太开心了的博客 5371

HttpClient详解(一)

http://www.cnblogs.com/anee/p/3269982.html HttpClient详解(一) 作者:namehybin更新于 08月15日 16:30访问(219)评论(0) HttpClient是一个客户端的HTTP通信实现库。HttpClient的目标是发送和接收HTTP报文。 HTTP请求 HttpClient 支持所有定

哈哈Boy的专栏 2091

多机器人协同:水下机器人集群的分布式控制与ROS仿真实践

本文探讨了多自主水下机器人(AUV)集群的分布式控制方法,重点分析了欠驱动6自由度AUV模型的反馈线性化技术。通过ROS/Gazebo仿真平台,详细介绍了系统架构设计、通信延迟补偿策略及环境扰动应对方案,为水下协同作业提供实用参考。

jupi8的博客 687

HTTPClient学习

最近有个日常要用到HttpClient,之前对这方面不了解,刚好借此机会学习一下并整理出来。  1、httpClient HttpClient是Apache中的一个开源的项目。它实现了HTTP标准中Client端的所有功能,使用它能够很容易地进行HTTP信息的传输。它的各个版本的使用方式都不太一样,我使用的版本是4.3.5的,网上比较多的资源是3.+版本的,目前最新已经有4.4+版本了

guanglihuan的专栏 1万+

配置权重_高盛都在用的资产配置模型,BL贝叶斯框架改进Markowitz

前面我们说到,markoviz的均值-方差模型,第一次,用数学的方式严格证明了投资组合存在最优的权重,但它的学术意义大于实战。主要原因有两个:1,人们很难有效的预测期望收益率;2,最优资产组合配置对输入非常敏感,结果往往难以被人理解。还有就是在投资中,定量只是完成初步构建,同步的定性判断依然非常重要:第一,投资者的认知偏好:倾向于关注他们认为被低估,但有发展潜力或者可以确定相对交易价值的小部分股票...

weixin_39892309的博客 715

Cadence16.6安装教程

如需安装所需的软件,请到文章末尾处查看 安装步骤: 安装前先关闭杀毒软件和360卫士,注意安装路径不能有中文,安装包路径也不要有中文。 试装系统:win10 64bit 1.解压安装包(共5个压缩包,每个都要解压) 2.以管理员身份运行安装程序。 3.选择License Manager。 4.点击NEXT。 5.选择I accept,然后点击NEXT。 6.选择License Manage...

谢谢关注“小鱼教你模数电”,各平台同号 8万+

如何快速上手Spotify Web API Java客户端:完整开发指南

Spotify Web API Java客户端是一个强大的Java库,让开发者能够轻松与Spotify Web API交互,实现音乐数据查询、播放控制等功能。本教程将带你快速掌握这个库的使用方法,从环境搭建到实际应用,让你在项目中轻松集成Spotify的丰富功能。 ## 📋 准备工作 ### 系统要求 - Java 9或更高版本 - Maven构建工具 - Spotify开发者账号(用于获取

gitblog_00868的博客 927

从零开始:在Unity中使用Dynamic Bone实现角色骨骼自然抖动(以女性角色胸部为例)

本文详细介绍了在Unity中使用Dynamic Bone插件实现角色骨骼自然抖动的完整流程,特别以女性角色胸部为例。从插件导入、骨骼系统基础到Dynamic Bone组件配置和参数调优,提供了全面的技术指导。文章还包含性能优化技巧和常见问题解决方案,帮助开发者快速掌握这一物理效果实现方法。

weixin_28728495的博客 454

Symfony HttpClient实战教程:构建高性能Web爬虫的完整指南

Symfony HttpClient是一个功能强大的HTTP客户端库,提供了同步和异步获取HTTP资源的方法,是构建高性能Web爬虫的理想选择。本教程将详细介绍如何利用Symfony HttpClient的核心功能,从零开始打造一个高效、可靠的Web爬虫系统。 ## 一、Symfony HttpClient简介:为什么选择它构建Web爬虫? Symfony HttpClient是Symfony

gitblog_00797的博客 318

开源滑翔伞升降速度表:基于STM32与传感器融合的DIY飞行仪表

传感器融合是现代嵌入式系统与物联网设备中的核心技术,它通过整合多个传感器的数据,利用滤波与估计算法,获得比单一传感器更精确、更可靠的环境感知能力。其技术价值在于提升系统的鲁棒性、精度和上下文理解能力,广泛应用于无人机导航、可穿戴设备、工业监测及智能驾驶等领域。本文聚焦于一个具体的工程实践案例——开源多功能滑翔伞升降速度表(Open-Vario),该项目巧妙地运用了**卡尔曼滤波器**进行气压与GNSS数据的融合,以精确计算升降率,并基于**FreeRTOS**实时操作系统构建了一个稳定、可扩展的嵌入式平台,

weixin_33657398的博客 176

【Android逆向工程】第18章:Ollvm 混淆与对抗

本章介绍了Ollvm混淆技术及其对抗方法。Ollvm是基于LLVM的开源代码混淆工具,主要实现控制流平坦化、虚假控制流和指令替换三种混淆技术。控制流平坦化通过状态变量和switch-case结构隐藏真实控制流,将原本清晰的逻辑拆分为多个状态块。混淆后的代码在静态分析中难以理解,但可通过动态追踪执行路径、符号执行等方法来还原原始逻辑。本章还提供了混淆代码示例和对抗策略,帮助理解Ollvm的工作原理及其防御方法。

w987333120的博客 213

:Blazor 全栈开发——告别 JavaScript 焦虑

专注于业务逻辑的后端同学来说,简直是噩梦。微软也意识到了这个痛点,于是 Blazor 诞生了。Blazor 的核心理念很简单:用 C# 替代 JavaScript。你可以在 Razor 页面里写 C# 代码,处理点击事件,甚至直接操作 DOM(虽然不推荐)。这让 .NET 开发者拥有了无缝的全栈开发能力。

pTfpyXoRz的博客 190

YOLO-V8训练自己的数据集之标注样本

四、标注样本 4.1、标注样本概述 4.1.1、样本标注主要方法 4.1.2、标注样本概念 4.1.3、标注样本实现方式 4.1.4、常见标注样本软件 4.2、标注工具LabelImg 4.2.1、LabelImg介绍 4.2.2、LabelImg特点 4.2.3、LabelImg安装方法 4.2.4、LabelImg使用方法 4.3、标注样本实操 4.3.1、安装标注软件Labelimg 4.3.2、Labelimg界面介绍 4.3.3、LabelImg实操过程中常

qq_29633789的博客 664

码农刚子 - 专注于C#/.NET的技术博主和开发者

为了接收 JSON 数据,我们需要定义一个简单的 DTO 类。在项目中新建set;set;set;理解了 Blazor Server 的实时通信原理。学会了使用@inject注入服务。实现了从后端 API 获取数据、删除数据和提交数据。掌握了双向绑定简化表单开发。现在的你,已经具备了独立开发一个小型管理系统的能力:后端用 Minimal API + EF Core,前端用 Blazor Server,全部用 C# 贯通。下一篇预告我们的应用已经能跑能跳了,但在互联网上裸奔是很危险的。

bkYovXq8B的博客 254

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

TI瑞士轮观赛指南:从BP博弈到数据复盘,解析Iron Wing对阵Falcons

在电竞赛事中,数据分析与复盘方法正在成为观众理解比赛的核心工具。以Dota2国际邀请赛(TI)为例,瑞士轮赛制下每场BO1都充满变数,强队与黑马的胜负往往取决于版本理解与BP策略的临场博弈。通过构建分析框架,从英雄池深度、经济曲线、视野控制等维度拆解比赛,能够帮助爱好者更专业地捕捉战术细节。本文结合Iron Wing与Falcons的对阵,介绍赛事数据平台的使用、录像复盘的五步法,以及如何将定性观察与定量指标结合,规避常见误区。无论新老观众,掌握这套方法都能提升观赛深度,从“看热闹”进阶为“看门道”。

weixin_34321753的博客 514

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

对python3标准库httpclient的使用详解

今天小编就为大家分享一篇对python3标准库httpclient的使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 如下所示: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ...

weixin_45550143的博客 2980

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【HTTPClient】HttpClient框架详解

HttpClient简介 HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。虽然在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。HttpClient 是 Apache Jakarta C

9721

访问web资源之httpclient使用入门

一、httpclient引入话题 作为web开发,我们知道访问tomcat所部属的网站,很多情况下会使用浏览器进行访问web。但我们今天了解一下通过客户端的方式来访问web资源,get或者post的方式进行简单demo的演示。可能我们会问在什么情况下需要通过客户端编程的方式进行访问。那我这边先不阐述这是具体何用的。以后具体用到实际场景的时候才引入。 二、httpclient简单背景介绍 H

TechBirds在路上 2847

C# httpclient获取cookies实现模拟web登录

C# httpclient获取cookies实现模拟web登录 目前在公司做一款平台化的产品,我主要负责PC端上的开发,在产品推荐过程中为了节省开发时间很多功能模块没来得及做原生,用CEF嵌入了很多带功能web页面,与客户端进行交互从而实现功能。 在二期开发中,产品需求说明书中需要把登录功能放在客户端来做,这当中涉及到一个问题客户端做登入登出很简单,但是很难通知到web平台登入登出。 我的想...

cxu123321的博客 4316

HttpClient 详解

HttpClient 详解备注:01. 网络请求为耗时操作,需要在子线程进行处理;02. 网络请求必须在清单文件中配置 internet 权限;1.应用场景 web站点中有某些页面,不是通过一个简单的url就可以访问的,可能需要用户登录且具有相应的权限才可以访问的,这就需要涉及Session、Cookie的处理 为了更好的处理Web站点的请求,包括处理Session、Cookie等细节

hyl411136528的博客 708
上一篇: MyBatis-Plus 之快速入门
下一篇: Tomcat8 配置SSL
yyangqqian
博客等级 码龄15年 406粉丝 406原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值