整个四月份都在做服务器端推送接入的工作,第一期接入的平台只包括小米,魅族,华为。
其中,小米魅族是支持用户全量推送的,不需要客户端上报用户的pushId,接入过程比较方便快速。
华为则比较坑了:
开发文档写的烂;
不支持全量推送,需要客户端上报一个推送一个;
为了解决开发中遇到的一些问题,专门加了华为官方的开发者群,但是提的问题基本上没人回答,导致开发进度一度暂停。
通过其他渠道解决了开发中遇到的问题后,就把项目部署到测试服务器了,但是测试服务器上,项目并不像在本地开发时一样良好运行,在调用推送接口时出现了这个错误。
在华为的群里问了官方,但是没人理,其他开发者也没有遇到这种情况,只有自己找出原因了。
测试服务器与本地开发环境主要的不同有两点:
①测试服务器在日本,而我在中国大陆
②测试服务器是linux,我的电脑是Windows
接下来就是使用排除法排除了。
刚好公司在阿里云上还有一台闲置的linux服务器,在简单搭建环境后,我把项目部署到了这台阿里云服务器上,发现可以正常推送。
可以看出,同是linux服务器,中国区的ip访问华为推送后台是没有问题的,但是日本东京的ip不可以。那就应该是华为的后台限制了日本的ip访问了。
不过这个需要华为官方的确认。于是我找到产品经理,产品经理通过公司运营那边的关系,终于得到了华为的回复:不支持日本。
那就很尴尬了,毕竟公司的测试服以及以后生产服务器都在东京。
和其他同事讨论这个情况后,他们提出了一种解决办法:在国内搭建一个转发的服务,华为推送请求先从日本发到这个转发服务,通过转发服务发到华为后台,华为的响应也是按照这个路径处理。
在仔细考虑可行性后,认为可以这么处理,于是开干。
这个中转服务器要做的非常简单,就是原封不动的转发我们服务器的请求及华为服务器的响应。一个action类就可以满足了,具体代码如下:
@Controller
@RequestMapping(value = "push")
public class PushCtrl {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private static String apiUrl = "https://api.push.hicloud.com/pushsend.do"; // 应用级消息下发API
@ResponseBody
@RequestMapping(value = "doTransfer",method=RequestMethod.POST)
public void doTransfer(HttpServletRequest request,HttpServletResponse httpServletResponse)
throws Exception {
byte[] data = FileCopyUtils.copyToByteArray(request.getInputStream());
String jsonData = new String(data, "UTF-8");
JSONObject jo = JSONObject.fromObject(new String(request.getParameter("nsp_ctx")));
String appId = (String)jo.get("appId");
String postUrl = apiUrl + "?nsp_ctx=" + URLEncoder.encode("{\"ver\":\"1\", \"appId\":\"" + appId + "\"}", "UTF-8");
String response = httpPost(postUrl, jsonData, 50000, 50000);
httpServletResponse.setContentType("text/plain;charset=utf-8");
PrintWriter responseStream = httpServletResponse.getWriter();
responseStream.println(response);
responseStream.close();
}
@ResponseBody
@RequestMapping(value = "test",method=RequestMethod.GET)
public ModelMap test(ModelMap m) {
m.put("key", "value");
return m;
}
public String httpPost(String httpUrl, String data, int connectTimeout,
int readTimeout) throws Exception {
OutputStream outPut = null;
HttpURLConnection urlConnection = null;
InputStream in = null;
try {
URL url = new URL(httpUrl);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded; charset=UTF-8");
urlConnection.setConnectTimeout(connectTimeout);
urlConnection.setReadTimeout(readTimeout);
urlConnection.connect();
// POST data
outPut = urlConnection.getOutputStream();
outPut.write(data.getBytes("UTF-8"));
outPut.flush();
// read response
if (urlConnection.getResponseCode() < 400) {
in = urlConnection.getInputStream();
} else {
in = urlConnection.getErrorStream();
}
List<String> lines = IOUtils.readLines(in,
urlConnection.getContentEncoding());
StringBuffer strBuf = new StringBuffer();
for (String line : lines) {
strBuf.append(line);
}
logger.info(strBuf.toString());
return strBuf.toString();
} finally {
IOUtils.closeQuietly(outPut);
IOUtils.closeQuietly(in);
if (urlConnection != null) {
urlConnection.disconnect();
}
}
}
}
View Code
接下来,就是部署,测试,竟然真的可行。那这个问题就算是解决了。