游戏推广员如何推广引流,seo搜索引擎招聘,物流企业网站织梦模板,美容养生wordpress商城模板背景
有台服务器#xff0c;网卡绑定有2个ip地址#xff0c;分别为#xff1a; A#xff1a;192.168.111.201 B#xff1a;192.168.111.202 在这台服务器请求目标地址 C#xff1a;192.168.111.203 时必须使用B作为源地址才能访问目标地址C#xff0c;在这台服务器默认…背景
有台服务器网卡绑定有2个ip地址分别为 A192.168.111.201 B192.168.111.202 在这台服务器请求目标地址 C192.168.111.203 时必须使用B作为源地址才能访问目标地址C在这台服务器默认又是使用A地址作为源地址。
1、curl解决办法
#指定源ip
curl -X POST -H Content-Type:application/json --interface 192.168.111.202 http://192.168.111.203:8080/v1 -d {model:x}2、使用nginx解决办法 #转发接口location ^~ /v1 {root html;limit_rate 2048k;proxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;client_max_body_size 100m;client_body_buffer_size 128m;proxy_connect_timeout 120s;proxy_send_timeout 120s;proxy_read_timeout 120s;proxy_bind 192.168.111.202; # 指定源IPproxy_pass http://192.168.111.203:8080;}
3、使用socket实现HTTP请求
由于原生HttpURLConnection不支持设置源ip地址而socket支持设置源ip地址所以使用socket实现http请求就可以了。
HttpURLConnection 示例 /*** 发送POST请求* param url 请求地址* param params 请求参数* param contentType ContentType请求头类型* param timeout 读超时单位秒* author lhs* date 2024/12/2 15:35*/public static String sendPost(String url, String params, String contentType, Integer timeout) {InputStream inputStream null;OutputStream outputStream null;HttpURLConnection connection null;int responseCode 0;try {connection (HttpURLConnection) new URL(url).openConnection();connection.setRequestMethod(POST);connection.setDoInput(true);connection.setDoOutput(true);connection.setUseCaches(false);connection.setConnectTimeout(10000);// 连接超时单位毫秒if (timeout null || timeout 0) {connection.setReadTimeout(15000);// 读超时单位毫秒} else {connection.setReadTimeout(timeout * 1000);// 读超时单位毫秒}if (contentType null || contentType.length() 0) {connection.setRequestProperty(Content-Type, APPLICATION_FORM_URLENCODED);} else {connection.setRequestProperty(Content-Type, contentType);}if (params ! null params.length() 0) {outputStream connection.getOutputStream();outputStream.write(params.getBytes(StandardCharsets.UTF_8));outputStream.flush();}int len;byte[] buf new byte[4096];responseCode connection.getResponseCode();inputStream connection.getInputStream();ByteArrayOutputStream baos new ByteArrayOutputStream();while ((len inputStream.read(buf)) ! -1) {baos.write(buf, 0, len);baos.flush();}String result baos.toString(UTF-8);baos.close();return result;} catch (Exception e) {String cause e.getCause() null ? : e.getCause().getMessage();return Exception: responseCode : cause e.getMessage();} finally {try {if (inputStream ! null) {inputStream.close();}if (outputStream ! null) {outputStream.close();}if (connection ! null) {connection.disconnect();}} catch (IOException e) {log.error(e.getMessage(), e);}}} HttpURLConnection源码分析过程
入口connection.getInputStream() 情况一
当不能预先确定报文体的长度时不可能在头中包含Content-Length域来指明报文体长度此时就需要通过Transfer-Encoding域来确定报文体长度。 情况二
响应头有 Content-Length socket实现HTTP请求
socket实现http请求很简单抓包看下报文就知道了比较麻烦的是解析响应报文。 根据分析HttpURLConnection 源码可以看出响应报文解析需要区分响应头有Transfer-Encoding和响应头有 Content-Length 两种情况。
若需要指定源IP打开“指定源IP方式”后面的注释代码注释“不需要指定源IP方式”后面两行代码。
package com.study;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.net.www.MeteredStream;
import sun.net.www.http.ChunkedInputStream;import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;public class HttpClientUtil {private static final Logger log LoggerFactory.getLogger(HttpClientUtil.class);/*ContentType请求头类型*/public final static String APPLICATION_FORM_URLENCODED application/x-www-form-urlencoded;charsetutf-8;public final static String APPLICATION_JSON application/json;charsetutf-8;public final static String APPLICATION_SOAP_XML application/soapxml;charsetutf-8;public final static String MULTIPART_FORM_DATA multipart/form-data;charsetutf-8;public final static String APPLICATION_XML application/xml;charsetutf-8;public final static String TEXT_HTML text/html;charsetutf-8;public final static String TEXT_XML text/xml;charsetutf-8;public static void main(String[] args) throws Exception {String url http://www.7timer.info/bin/astro.php;String params lon104.06lat30.65ac0langenunitmetricoutputjsontzshift0;String result sendPost(url, params, HttpClientUtil.APPLICATION_FORM_URLENCODED, 20);log.info(响应报文 result);}/*** 发送POST请求* param url 请求地址* param params 请求参数* param contentType ContentType请求头类型* param soTimeout 读超时单位秒* author lhs* date 2024/12/2 15:35*/public static String sendPost(String url, String params, String contentType, Integer soTimeout) throws Exception {URL u new URL(url);String path u.getFile();if (path ! null !path.isEmpty()) {if (path.charAt(0) ?) {path / path;}} else {path /;}// 要连接的服务端IP地址和端口int port u.getPort();String host u.getHost();String authority host;if (port ! -1 port ! u.getDefaultPort()) {authority host : port;}if (port -1) {port u.getDefaultPort();}// 设置连接超时时间int connectTimeout 10 * 1000;// 不需要指定源IP方式Socket socket new Socket();socket.connect(new InetSocketAddress(host, port), connectTimeout);// 指定源IP方式// SocketAddress localAddress new InetSocketAddress(192.168.111.202, 0);// 0表示让系统自动选择一个端口// socket.bind(localAddress); // 绑定本地 IP 地址和端口// SocketAddress remoteAddress new InetSocketAddress(host, port);// socket.connect(remoteAddress, connectTimeout); // 连接到远程服务器OutputStream outputStream socket.getOutputStream();PrintStream serverOutput new PrintStream(new BufferedOutputStream(outputStream), false, UTF-8);socket.setTcpNoDelay(true);socket.setSoTimeout(soTimeout * 1000);// 请求参数body部分byte[] body params.getBytes(StandardCharsets.UTF_8);// // 请求参数header部分String header getHttpHeader(path, authority, contentType, body.length);log.info(请求报文 header params);serverOutput.print(header);//请求参数header部分serverOutput.flush();serverOutput.write(body);//请求参数body部分serverOutput.flush();InputStream inputStream new BufferedInputStream(socket.getInputStream());int len 0;byte[] buf new byte[8];// readlimit被设置为10意味着从标记位置开始你可以读取最多10个字节的数据然后仍然可以通过调用reset()方法回到这个标记位置。inputStream.mark(10);while (len 8) {int read inputStream.read(buf, len, 8 - len);if (read 0) {break;}len read;}String scheme new String(buf, StandardCharsets.UTF_8);inputStream.reset();if (HTTP/1.1.equals(scheme)) {MapString, String headerMap parseHeader(inputStream);try {//第一行响应内容String firstLineHeader headerMap.get(null);int index;for (index firstLineHeader.indexOf(32); firstLineHeader.charAt(index) ; index) {}//响应码int responseCode Integer.parseInt(firstLineHeader.substring(index, index 3));log.info(响应码 responseCode);// 当不能预先确定报文体的长度时不可能在头中包含Content-Length域来指明报文体长度此时就需要通过Transfer-Encoding域来确定报文体长度。String transferEncoding headerMap.get(Transfer-Encoding);if (chunked.equalsIgnoreCase(transferEncoding)) {inputStream new ChunkedInputStream(inputStream, sun.net.www.http.HttpClient.New(u), null);}//响应body长度String contentLength headerMap.get(Content-Length);if (contentLength ! null) {long bodyLength Long.parseLong(contentLength);inputStream new MeteredStream(inputStream, null, bodyLength);}buf new byte[4096];ByteArrayOutputStream baos new ByteArrayOutputStream();//只有当客户端关闭它的输出流的时候服务端才能取得结尾的-1while ((len inputStream.read(buf)) ! -1) {baos.write(buf, 0, len);}String result baos.toString(UTF-8);return result;} catch (Exception e) {e.printStackTrace();}}return null;}/*** 该方法参考sun.net.www.MessageHeader#mergeHeader(java.io.InputStream)源码* author lhs* date 2025/1/11 10:53*/private static MapString, String parseHeader(InputStream var1) throws IOException {MapString, String headerMap new HashMap();if (var1 ! null) {char[] var2 new char[10];String var9;String var10;for (int var3 var1.read(); var3 ! 10 var3 ! 13 var3 0; headerMap.put(var10, var9)) {int var4 0;int var5 -1;boolean var7 var3 32;var2[var4] (char) var3;label104:while (true) {int var6;if ((var6 var1.read()) 0) {var3 -1;break;}switch (var6) {case 9:var6 32;case 32:var7 false;break;case 10:case 13:var3 var1.read();if (var6 13 var3 10) {var3 var1.read();if (var3 13) {var3 var1.read();}}if (var3 10 || var3 13 || var3 32) {break label104;}var6 32;break;case 58:if (var7 var4 0) {var5 var4;}var7 false;}if (var4 var2.length) {char[] var8 new char[var2.length * 2];System.arraycopy(var2, 0, var8, 0, var4);var2 var8;}var2[var4] (char) var6;}while (var4 0 var2[var4 - 1] ) {--var4;}if (var5 0) {var10 null;var5 0;} else {var10 String.copyValueOf(var2, 0, var5);if (var5 var4 var2[var5] :) {var5;}while (var5 var4 var2[var5] ) {var5;}}if (var5 var4) {var9 new String();} else {var9 String.copyValueOf(var2, var5, var4 - var5);}}}return headerMap;}/*** 拼接http请求头报文* author lhs* date 2023/3/31 17:47*/private static String getHttpHeader(String path, String authority, String contentType, int length) throws Exception {StringBuilder header new StringBuilder();header.append(POST path HTTP/1.1\r\n);// header.append(Content-Type: application/json;charsetUTF-8\r\n);header.append(Content-Type: contentType \r\n);header.append(Host: authority \r\n);header.append(Content-Length: length \r\n);header.append(\r\n);return header.toString();}}