項目和起因
項目
- 一個類似于Server醬的消息推送應用,隻需通過一條URL即可給指定通道發送資訊,可以用來發送告警、伺服器狀态、腳本運作狀态等資訊,約等于以前很多人用的郵件通知。
- 目前隻寫了企業微信應用的通道,因為企業微信應用能在微信顯示,而微信最常用基本不會關。
- 以後應該會增加公衆号、釘釘等通道,再看看要不要支援多人的。
遇到的問題
- 版本:Java 1.8.0_333
- 在Linux下使用正常,在Windows下發送中文會不顯示或者亂碼。
問題原因和解決
原因
- Windows和Linux下Java預設編碼不同的問題。
- Windows下預設編碼是GBK,Linux下預設編碼是UTF-8。
- 這個對新手來說挺坑的,以前一直聽說Java跨平台好,沒想到能遇到這種問題。
- 在這之前用Python寫過一個Dome就沒遇到這種問題。
- 可以用這段代碼測試目前環境Java的預設編碼
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
class Test {
public static void main(String[] args) {
System.out.println("Default Charset=" + Charset.defaultCharset());
System.out.println("file.encoding=" + System.getProperty("file.encoding"));
System.out.println("Default Charset=" + Charset.defaultCharset());
System.out.println("Default Charset in Use=" + getDefaultCharSet());
}
private static String getDefaultCharSet() {
OutputStreamWriter writer = new OutputStreamWriter(new ByteArrayOutputStream());
String enc = writer.getEncoding();
return enc;
}
}
複制
探究和解決
探索粗記錄
項目基本邏輯
- 用SpringBoot寫一個API,用來接收請求,例如:
。http://127.0.0.1:8080/qw?msg=你好&token=123
- 對比token,如果token與預設的不同傳回錯誤資訊,不給使用API。
- token相同,調用企業微信API把
的資訊推送到手機。msg
其中發送POST、GET請求的類如下:
package hello;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Created by chengxia on 2018/12/4.
*/
public class HttpURLConnectionWX {
public String doPost(String URL,String jsonStr){
OutputStreamWriter out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
HttpURLConnection conn = null;
try{
URL url = new URL(URL);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
//發送POST請求必須設定為true
conn.setDoOutput(true);
conn.setDoInput(true);
//設定連接配接逾時時間和讀取逾時時間
conn.setConnectTimeout(30000);
conn.setReadTimeout(10000);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
//擷取輸出流
out = new OutputStreamWriter(conn.getOutputStream());
out.write(jsonStr);
out.flush();
out.close();
//取得輸入流,并使用Reader讀取
if (200 == conn.getResponseCode()){
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null){
result.append(line);
System.out.println(line);
}
}else{
System.out.println("ResponseCode is an error code:" + conn.getResponseCode());
}
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(out != null){
out.close();
}
if(in != null){
in.close();
}
}catch (IOException ioe){
ioe.printStackTrace();
}
}
return result.toString();
}
public String doGet(String URL){
HttpURLConnection conn = null;
InputStream is = null;
BufferedReader br = null;
StringBuilder result = new StringBuilder();
try{
//建立遠端url連接配接對象
URL url = new URL(URL);
//通過遠端url連接配接對象打開一個連接配接,強轉成HTTPURLConnection類
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
//設定連接配接逾時時間和讀取逾時時間
conn.setConnectTimeout(15000);
conn.setReadTimeout(60000);
conn.setRequestProperty("Accept", "application/json");
//發送請求
conn.connect();
//通過conn取得輸入流,并使用Reader讀取
if (200 == conn.getResponseCode()){
is = conn.getInputStream();
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String line;
while ((line = br.readLine()) != null){
result.append(line);
System.out.println(line);
}
}else{
System.out.println("ResponseCode is an error code:" + conn.getResponseCode());
}
}catch (MalformedURLException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(br != null){
br.close();
}
if(is != null){
is.close();
}
}catch (IOException ioe){
ioe.printStackTrace();
}
conn.disconnect();
}
return result.toString();
}
public static void main(String[] args) throws Exception {
// 測試用
new HttpURLConnectionWX().doPost("http://127.0.0.1:5000/qwtx", new String("{\"name\":\"你好\"}".getBytes("UTF-8")));
}
}
複制
嘗試
- 使用
進行轉碼,無效。new String(msg.getBytes("UTF-8"))
- 使用
進行轉碼,無效。new String(msg.getBytes("GBK"))
- 更改POST請求函數中的
為GBK,無效。in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
上面的 無效
指的是以下效果:直接是空的(一般是純文字資訊會遇到)、前部分文字能顯示最後一個是亂碼(一般是文字+數字/英文)、全是亂碼(瞎改代碼裡面的編碼轉換後遇到的)
更多奇怪的嘗試就不說了,當時已經知道通過加參數運作可以指定編碼,但是感覺那樣還得按照系統改指令不夠人性化,就一直在嘗試。
最後還是放棄了,沒找到方法,等以後真正系統學了Java再說吧。
- 最後放個輔助測試的Python腳本
import charset_normalizer
from flask import Flask, request
import json
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'hello world'
@app.route('/qw', methods=['POST'])
def register():
byu = request.stream.read()
# print(request.headers)
print(charset_normalizer.detect(byu))
try:
print(str(byu ,encoding='GBK'))
except:
print('GBK ERR')
try:
print(str(byu,encoding='UTF-8'))
except:
print('UTF-8 ERR')
return 'welcome'
if __name__ == '__main__':
app.run(port=5000, debug=True)
複制
解決
參考:設定Java JDK的預設編碼為UTF-8_lc11535的部落格-CSDN部落格_java設定utf-8
- 添加一個名為
的系統環境變量,變量值為JAVA_TOOL_OPTIONS
,參考官網說明。-Dfile.encoding=UTF-8
- 每次運作時都加一個
-Dfile.encoding=UTF-8
的參數。
如果是添加系統環境變量,添加完後需要重新開機CMD視窗才生效,可以用開頭的檢測預設編碼的代碼測試看看是否生效
未嘗試:看B站有回複說Java 18把Win和Linux的預設編碼都改成UTF-8了