服务器端接入华为推送遇到的connection reset问题

整个四月份都在做服务器端推送接入的工作,第一期接入的平台只包括小米,魅族,华为。

其中,小米魅族是支持用户全量推送的,不需要客户端上报用户的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

接下来,就是部署,测试,竟然真的可行。那这个问题就算是解决了。

 

posted @ 2018-05-07 14:03  影卓后台开发人员  阅读(3195)  评论(0编辑  收藏  举报