一、依赖项
Maven
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
第三方工具
【HttpUtil】基于HttpClient的Http工具类
二、源代码
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.Getter;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@SuppressWarnings({"UnusedReturnValue", "BooleanMethodIsAlwaysInverted"})
public class ImgtuUtil {
static final String IMGTU_USER_NAME = "ACCOUNT";
static final String IMGTU_PASSWORD = "PASSWORD";
static final Logger log = LogManager.getLogger(ImgtuUtil.class);
static final private String IMGTU_INIT_URL = "https://imgtu.com/init";
static final private String IMGTU_LOGIN_URL = "https://imgtu.com/login";
static final private String IMGTU_OPERATE_URL = "https://imgtu.com/json";
static final private Pattern SESSION_ID_PATTERN = Pattern.compile("PHPSESSID=([^;]*); path=/; HttpOnly");
static final private Pattern AUTH_TOKEN_PATTERN = Pattern.compile("PF\\.obj\\.config\\.auth_token = \"([0-9a-f]{40})\";");
static final private Pattern KEEP_LOGIN_PATTERN = Pattern.compile("KEEP_LOGIN=([^;]*);");
static final private long INIT_VALID_DURATION = 15L * 60 * 1000;
static final private long LOGIN_VALID_DURATION = 30L * 24 * 60 * 60 * 1000;
@Getter
static private String sessionId;
@Getter
static private String authToken;
@Getter
static private String keepLogin;
@Getter
static private long initTimestamp = 0;
@Getter
static private long loginTimestamp = 0;
public static boolean initSession() {
return initSession(false);
}
public static boolean initSession(boolean forceAction) {
log.info("-------->>>> 图床·初始化会话 <<<<--------");
if (!forceAction && initTimestamp + INIT_VALID_DURATION > System.currentTimeMillis()) {
log.info("【初始化】成功:会话有效期内,无需重新初始化。");
return true;
}
synchronized (ImgtuUtil.class) {
sessionId = null;
authToken = null;
String httpRawString;
CloseableHttpResponse httpResponse;
try {
httpResponse = HttpUtil.get(IMGTU_INIT_URL, new HashMap<>(0), new HashMap<>(0));
HttpEntity httpEntity = httpResponse.getEntity();
httpRawString = EntityUtils.toString(httpEntity);
} catch (IOException e) {
log.error("【初始化】失败:请求页面失败。");
e.printStackTrace();
return false;
}
Header[] responseHeaders = httpResponse.getAllHeaders();
for (Header header : responseHeaders) {
if ("Set-Cookie".equalsIgnoreCase(header.getName())) {
String cookies = header.getValue();
Matcher matcher = SESSION_ID_PATTERN.matcher(cookies);
if (matcher.find(0)) {
sessionId = matcher.group(1);
}
}
}
if (sessionId == null) {
log.error("【初始化】失败:获取SessionId失败。");
return false;
}
Matcher matcher = AUTH_TOKEN_PATTERN.matcher(httpRawString);
if (matcher.find(0)) {
authToken = matcher.group(1);
} else {
log.error("【初始化】失败:获取AuthToken失败。");
return false;
}
log.info("【初始化】成功:");
log.info("【初始化】SessionId:" + sessionId);
log.info("【初始化】AuthToken:" + authToken);
initTimestamp = System.currentTimeMillis();
return true;
}
}
public static boolean login() throws IOException {
return login(false);
}
public static boolean login(boolean forceAction) throws IOException {
log.info("-------->>>> 图床·登录 <<<<--------");
if (!forceAction && loginTimestamp + LOGIN_VALID_DURATION > System.currentTimeMillis()) {
log.info("【登录】成功:登录状态有效期内,无需重新登录。");
return true;
}
synchronized (ImgtuUtil.class) {
initSession();
Map<String, String> headers = new HashMap<>(3);
headers.put("cookie", "PHPSESSID=" + sessionId + ";");
headers.put("content-type", "application/x-www-form-urlencoded");
headers.put("connection", "keep-alive");
CloseableHttpResponse httpResponse = HttpUtil.post(IMGTU_LOGIN_URL, new HashMap<>(0), headers, "login-subject=" + IMGTU_USER_NAME + "&password=" + IMGTU_PASSWORD + "&auth_token=" + authToken);
Header[] responseHeaders = httpResponse.getAllHeaders();
for (Header header : responseHeaders) {
if ("Set-Cookie".equalsIgnoreCase(header.getName())) {
String cookies = header.getValue();
Matcher matcher = KEEP_LOGIN_PATTERN.matcher(cookies);
if (matcher.find(0)) {
keepLogin = matcher.group(1);
}
}
}
if (keepLogin != null) {
loginTimestamp = System.currentTimeMillis();
log.info("【登录】成功:");
log.info("【登录】KeepLogin:" + keepLogin);
return true;
} else {
log.error("【登录】失败:");
log.error("【登录】StatusCode:" + httpResponse.getStatusLine().getStatusCode());
return false;
}
}
}
public static boolean ensureLogin() throws IOException {
return initSession() && login();
}
public static JsonObject upload(byte[] bytes, String fileName, ContentType fileType) throws IOException {
log.info("-------->>>> 图床·上传 <<<<--------");
if (!ensureLogin()) {
log.error("【上传】失败:服务不可用。");
return null;
}
Map<String, String> headers = new HashMap<>(3);
headers.put("Cookie", "PHPSESSID=" + sessionId + "; KEEP_LOGIN=" + keepLogin);
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36");
headers.put("Connection", "keep-alive");
try {
Map<String, ContentBody> params = new HashMap<>(6);
params.put("source", new ByteArrayBody(bytes, fileType, fileName));
params.put("type", new StringBody("file", ContentType.MULTIPART_FORM_DATA));
params.put("action", new StringBody("upload", ContentType.MULTIPART_FORM_DATA));
params.put("timestamp", new StringBody(Long.toString(System.currentTimeMillis()), ContentType.MULTIPART_FORM_DATA));
params.put("auth_token", new StringBody(authToken, ContentType.MULTIPART_FORM_DATA));
params.put("nsfw", new StringBody("0", ContentType.MULTIPART_FORM_DATA));
CloseableHttpResponse httpResponse = HttpUtil.multipart(IMGTU_OPERATE_URL, new HashMap<>(0), headers, params);
String httpRawString = EntityUtils.toString(httpResponse.getEntity());
log.info("【上传】成功:上传成功。");
return new Gson().fromJson(httpRawString, JsonObject.class);
} catch (IOException e) {
log.error("【上传】失败:上传失败。");
e.printStackTrace();
return null;
}
}
public static JsonObject delete(String deleteId) throws IOException {
log.info("-------->>>> 图床·删除 <<<<--------");
if (!ensureLogin()) {
log.error("【删除】失败:服务不可用。");
return null;
}
Map<String, String> headers = new HashMap<>(3);
headers.put("Cookie", "PHPSESSID=" + sessionId + "; KEEP_LOGIN=" + keepLogin);
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36");
headers.put("Connection", "keep-alive");
try {
Map<String, ContentBody> params = new HashMap<>(5);
params.put("auth_token", new StringBody(authToken, ContentType.MULTIPART_FORM_DATA));
params.put("action", new StringBody("delete", ContentType.MULTIPART_FORM_DATA));
params.put("single", new StringBody("true", ContentType.MULTIPART_FORM_DATA));
params.put("delete", new StringBody("image", ContentType.MULTIPART_FORM_DATA));
params.put("deleting[id]", new StringBody(deleteId, ContentType.MULTIPART_FORM_DATA));
CloseableHttpResponse httpResponse = HttpUtil.multipart(IMGTU_OPERATE_URL, new HashMap<>(0), headers, params);
String httpRawString = EntityUtils.toString(httpResponse.getEntity());
log.info("【删除】成功:删除成功。");
return new Gson().fromJson(httpRawString, JsonObject.class);
} catch (IOException e) {
log.error("【删除】失败:删除失败。");
e.printStackTrace();
return null;
}
}
}
三、使用方法
- 使用前,请先注册一个图床帐号,然后将
用户名 和 密码 分别填写在 IMGTU_USER_NAME 和 IMGTU_PASSWORD 两个变量的初始值上。 - 使用时,可直接调用
upload 或 delete 方法,会自动判断是否需要 初始化会话 或 重新登录 。 - 如果你需要保证更快的文件上传,可定期手动调用
initSession(true) 。 - 默认
PHPSESSID 有效期为15分钟, KeepLogin 有效期为30天,若出现报错可以酌情减少间隔。 - 因图床限制,若使用VPN代理可能会导致请求被拒绝。
四、基本流程
- 请求
https://imgtu.com/init ,从返回的 404页面 中获取 PHPSESSID 和 token 。 - 请求
https://imgtu.com/login ,完成 登录 。 - 使用
https://imgtu.com/json 进行 上传 和 删除 操作。
|