QQ登录网站接入功能实现--非官方文档搬运

news/2024/5/9 21:41:32/文章来源:https://xuliugen.blog.csdn.net/article/details/50010647

背景

最近第一次使用QQ登录功能,期间遇到这种问题,在网上找了很多资料,大多都是官方的搬运,并没有真正的干料,可能是个人能力问题,遇到了各种麻烦,折腾了几天,最终弄好,在这里记录一下和大家分享,希望对大家有所帮助。

由于官方文档已经对如何使用API接口做出了很明确的说明,所以这里我只是记录我在开发过程中一些步骤中遇到的问题和注意的事项,详细步骤请参考官方文档:http://wiki.connect.qq.com/

开发环境:SpringMVC、QQ登录Java SDK版、Maven、IDEA

应用部署和常见问题解决

访问QQ互联的地址如下:http://connect.qq.com/,这里是需要开发者进行注册登录验证的网址

一、账户登录
注意:登录的账户尽量用公司专用的,以后用于测试的时候,只能这个账户进行测试,这样的话,可以减少不必要的麻烦或者泄露自己的QQ信息,另外在本地是可以进行测试的,网上流传的本地不可测试的说法是不正确的,官方Demo中已经明确给出了具体的本地测试方法:(本地测试未进行验证,不做研究)

如果在本机tomcat或其他服务器下部署请配置本地host文件:127.0.0.1 您的回调域名直接部署运行,将sdk4j_demo目录中的web目录直接放在tomcat服务器的webapp目录即可,配置conf/server.xml文件中的host的context<Context docBase="web" path="/" privileged="true" antiResourceLocking="false"></Context>
并将webapp目录下的Root 文件夹暂时移除。
其他服务器请参照服务器自身部署方法。**请将服务器的端口号配置至80端口**。
配置host:127.0.0.1 您的回调域名   访问首页  您的回调域名/index.jsp
网站首页 index.jsp 引导用户到 IndexServlet
IndexServlet 用到了 SDK中的 com.qq.connect.oauth.Oauth.getAuthorizeURL(..) 方法来获取应该引导用户跳转的地址
。。。(详见Demo中的ReadMe.txt文件)

二、注册开发者账户
如果已经注册,则不会有该步骤,没有的话根据相应的需求进行注册

三、创建应用

首先可以根据官方案例进行编写自己的项目,http://qzonestyle.gtimg.cn/qzone/vas/opensns/res/doc/qqConnect_Server_SDK_java_v2.0.zip
(或者可访问:http://wiki.connect.qq.com/sdk%E4%B8%8B%E8%BD%BD)

项目代码完成之后,可以继续下边的内容:

这里写图片描述

在这一块我相信是很多人遇到的问题,第一个是网站地址该如何填写,另一个是回调地址的填写,尽管填写完成还会有相应的报错,下边做一下我的分析:

1、网站地址的选取:首先是官网的首页或登陆界面,在域名解析的时候必须为80端口(我尝试过其他端口是不可以的)

这里写图片描述

上图是一个域名的解析,例如:www.abc.com是我的域名,111.23.23.244是我的主机,图中有三条记录

第一条是将域名和主机IP地址进行绑定;
第二条是将二级域名dubboadmin进行解析,即www.dubboadmin.abc.com;
第三条是将二级域名security进行解析,即www.security.abc.com;;

此时可以看出,dubboadmin和security都是二级域名,一个是通过A记录一个是通过隐形URL的类型,这是因为,在默认的域名解析中,如果通过A记录来绑定域名的话,默认的是绑定到IP的80端口,即111.23.23.244:80,但是一个IP绑定主机上的端口还有很多,一个IP主机机器上可以运行多个项目,这样的话我们就通过隐形URL的方式来将不同的二级域名绑定到不同的端口上,即是将dubboadmin绑定到http://www.abc.com:8012端口上.

我在做QQ登录的时候,亲测过使用其他端口的不可行,请看下图:

这里写图片描述

这个是我使用的该域名下绑定的8011端口,打开网页时的界面,这里边明显的是一个framenset将doucument中的内容进行包裹,在最外层的html下的head中并没有需要添加的meta信息,而真正的我们的网页信息,是document包裹内的东西,游览前只是根据非80端口的服务器网页内容做了一次封装显示在网页中,而qq在验证网站的时候,找的是该网页head中的meta信息,因此会验证失败。这一点也在官方Demo的ReadMe.txt文件中明确指出了使用80端口。

所以,如果你在开发的过程中也是出现使用IP非80端口绑定的域名遇到了验证失败这个问题,请使用80端口进行测试。

最后,根据80端口,我绑定的域名是www.security.abc.com,但是还要注意的是,对于任何一个用户在访问www.security.abc.com地址的时候,有可能会让用户登录,那么会跳转到一个登录界面,例如我的就是当访问www.security.abc.com的时候,他会自动跳到security.abc.com/login.do让用户登录,那我我最终的网站地址就是:http://security.abc.com/login.do,因为,这个网址也是QQ在验证网站的时候进行访问的链接(可以打log进行查看),因此使用http://security.abc.com/ 是不可以的。(虽然,我在服务器处理的是,访问www.security.abc.com如果用户没有登录会自动跳转到http://security.abc.com/login.do,但是直接写http://security.abc.com/验证是失败的,具体不清楚是不是qq在验证的时候直接找http://security.abc.com/下的界面,这个还需后边的测试去验证)

这里写图片描述

同样的在这个login界面,也就是http://security.abc.com/login.do所指向的界面中添加QQ登录按钮,和网站验证时需要填写在head标签中的meta信息,例如:

<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta property="qc:admins" content="1133201050a16asdfhjsdf7sd5f6567647"/><title>QQ登录测试</title>
</head>
<div class="form-group input-group" style="margin-top: 45px;"><a href="/qqlogin.do">请使用你的QQ账号登陆</a>
</div>

这里的/qqlogin.do是进行登录处理的controller地址,在后边会说

2、回调地址的选择

回调地址的选择是在用户通过QQ授权之后,我们需要对用户信息进行保存的地址,由于使用的是SpringMVC,所以后缀的时候有个do,例如我的回调操作如下:(代码为官方Demo案例,可以直接使用)

@Controller
@RequestMapping
public class LoginController {@Injectprivate Oauth qqOauth;/*** 进行QQ登录,这里就是前台界面中访问的那个超链接的处理Controller*/@RequestMapping(value = "/qqlogin")public void QQLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {response.setContentType("text/html;charset=utf-8");try {response.sendRedirect(qqOauth.getAuthorizeURL(request));} catch (QQConnectException e) {e.printStackTrace();}}/*** 用于QQ登录的回调,进行用户信息的保存操作等*/@RequestMapping(value = "/afterQQLogin")protected void afterQQLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {response.setContentType("text/html; charset=utf-8");PrintWriter out = response.getWriter();try {AccessToken accessTokenObj = (new Oauth()).getAccessTokenByRequest(request);String accessToken = null, openID = null;long tokenExpireIn = 0L;//这还有很多代码,是在上边的那个官方案例中给出的,或者在最下边的代码中,请参考使用} catch (QQConnectException e) {}}
}

因此我的回调地址是:http://security.abc.com/afterQQLogin.do

如果你的项目代码中完成了以上部分的话,可以将项目部署到真实的域名下,然后进行验证。

3、项目的配置文件

如果上述过程OK,则在官方demo中还有一个名为:qqconnectconfig.properties的配置文件,这个是需要配置的:

app_ID = 34234123 #自己申请的id
app_KEY = ecfd12341234qewrqwer69db492e1ca #自己申请的key
redirect_URI = http://security.abc.com/afterQQLogin.do #回调地址
scope=get_user_info,add_topic,add_one_blog,add_album,upload_pic,list_album,add_share,check_page_fans,add_t,add_pic_t,del_t,get_repost_list,get_info,get_other_info,get_fanslist,get_idollist,add_idol,del_ido,get_tenpay_addr
#下边还有很多,因为是不需要修改的,所以不具体列出

这里提示:别忘了引用qq登录的jar包

官方Demo中介绍的是该文件要放在src目录下,这是在传统的通过MyEclipse中创建的静态Web项目的做法,如果使用的是Spring框架的话,把该文件放在src目录下的话会出现bean加载失败的问题,则需要将该文件放在resource目录下,这样的话,在进行项目启动的时候就可以加载到。

这里写图片描述

另外,如果将该文件放在了正确的位置,还是出现bean未加载的问题的话,如果出现下边的错误:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.qq.connect.oauth.Oauth org.albert.security.controller.LoginController.qqOauth; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.qq.connect.oauth.Oauth] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.inject.Inject()}

我的解决方法是手动配置该Oauth,在spring配置文件的相应位置放入

<bean id="qqOauth" class="com.qq.connect.oauth.Oauth"/>

在使用的位置添加:

 @Injectprivate Oauth qqOauth;

并将案例中response.sendRedirect(new Oauth().getAuthorizeURL(request));的代码对应的改为response.sendRedirect(qqOauth.getAuthorizeURL(request));(可以将Demo中的代码和最下边我提供的代码进行比较,可以发现修改的地方,就是在Oauth类实例化的时候进行手动的装配bean)

这样的话,在我的项目中可以跑起来,QQ登录的功能也可以使用。

其他问题

1、官方对应错误返回码文档说明如下:http://wiki.connect.qq.com/公共返回码说明

2、如果使用IDEA+maven项目的开发方式的话,那么怎么引用qq的依赖jar哪?
过程如下:在WEB-INF 目录下创建一个lib目录,将该jar放进去,然后再对应的POM文件中加入:

<dependency><groupId>javabuilder</groupId><artifactId>javabuilder</artifactId><version>1.0</version><scope>system</scope><systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/Sdk4J.jar</systemPath>
</dependency>

systemPath为自己对应的位置,即可完成对jar的依赖,另外别忘了将在Sdk4J.jar上右键将改jar加入到classpath中。

3、javax.net.ssl.SSLKeyException

在使用QQ官方的api方法时,如果在QQ api代码中报出一下异常

javax.net.ssl.SSLKeyException: [Security:090477]Certificate chain received from ebanktest.95559.com.cn - 124.74.249.16 was not trusted causing SSL handshake failure

请将jdk的版本设置为sun jdk而不是openjdk

[root@VM_92_170_centos home]# java -version
java version "1.7.0_79"
Java(TM) SE Runtime Environment (build 1.7.0_79-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)
[root@VM_92_170_centos home]# 

—————————————————分割线——————————————————-
另附我在项目中是使用的Controller:

@Controller
@RequestMapping
public class LoginController {private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class);@Injectprivate Oauth qqOauth;/*** 进行QQ登录* @param request* @param response* @throws IOException*/@RequestMapping(value = "/qqlogin")public void QQLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {response.setContentType("text/html;charset=utf-8");try {response.sendRedirect(qqOauth.getAuthorizeURL(request));} catch (QQConnectException e) {e.printStackTrace();}}/*** 用于QQ登录的回调*/@RequestMapping(value = "/afterQQLogin")protected void afterQQLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {response.setContentType("text/html; charset=utf-8");PrintWriter out = response.getWriter();try {AccessToken accessTokenObj = (new Oauth()).getAccessTokenByRequest(request);String accessToken = null, openID = null;long tokenExpireIn = 0L;if (accessTokenObj.getAccessToken().equals("")) {
//                我们的网站被CSRF攻击了或者用户取消了授权
//                做一些数据统计工作System.out.print("没有获取到响应参数");} else {accessToken = accessTokenObj.getAccessToken();tokenExpireIn = accessTokenObj.getExpireIn();request.getSession().setAttribute("demo_access_token", accessToken);request.getSession().setAttribute("demo_token_expirein", String.valueOf(tokenExpireIn));// 利用获取到的accessToken 去获取当前用的openid -------- startOpenID openIDObj = new OpenID(accessToken);openID = openIDObj.getUserOpenID();out.println("欢迎你,代号为 " + openID + " 的用户!");request.getSession().setAttribute("demo_openid", openID);
//                out.println("<a href=" + "/shuoshuoDemo.html" + " target=\"_blank\">去看看发表说说的demo吧</a>");// 利用获取到的accessToken 去获取当前用户的openid --------- endout.println("<p> start -----------------------------------利用获取到的accessToken,openid 去获取用户在Qzone的昵称等信息 ---------------------------- start </p>");UserInfo qzoneUserInfo = new UserInfo(accessToken, openID);UserInfoBean userInfoBean = qzoneUserInfo.getUserInfo();out.println("<br/>");if (userInfoBean.getRet() == 0) {out.println(userInfoBean.getNickname() + "<br/>");out.println(userInfoBean.getGender() + "<br/>");out.println("黄钻等级: " + userInfoBean.getLevel() + "<br/>");out.println("会员 : " + userInfoBean.isVip() + "<br/>");out.println("黄钻会员: " + userInfoBean.isYellowYearVip() + "<br/>");out.println("<image src=" + userInfoBean.getAvatar().getAvatarURL30() + "/><br/>");out.println("<image src=" + userInfoBean.getAvatar().getAvatarURL50() + "/><br/>");out.println("<image src=" + userInfoBean.getAvatar().getAvatarURL100() + "/><br/>");} else {out.println("很抱歉,我们没能正确获取到您的信息,原因是: " + userInfoBean.getMsg());}out.println("<p> end -----------------------------------利用获取到的accessToken,openid 去获取用户在Qzone的昵称等信息 ---------------------------- end </p>");out.println("<p> start ----------------------------------- 验证当前用户是否为认证空间的粉丝------------------------------------------------ start <p>");PageFans pageFansObj = new PageFans(accessToken, openID);PageFansBean pageFansBean = pageFansObj.checkPageFans("97700000");if (pageFansBean.getRet() == 0) {out.println("<p>验证您" + (pageFansBean.isFans() ? "是" : "不是") + "QQ空间97700000官方认证空间的粉丝</p>");} else {out.println("很抱歉,我们没能正确获取到您的信息,原因是: " + pageFansBean.getMsg());}out.println("<p> end ----------------------------------- 验证当前用户是否为认证空间的粉丝------------------------------------------------ end <p>");out.println("<p> start -----------------------------------利用获取到的accessToken,openid 去获取用户在微博的昵称等信息 ---------------------------- start </p>");com.qq.connect.api.weibo.UserInfo weiboUserInfo = new com.qq.connect.api.weibo.UserInfo(accessToken, openID);com.qq.connect.javabeans.weibo.UserInfoBean weiboUserInfoBean = weiboUserInfo.getUserInfo();if (weiboUserInfoBean.getRet() == 0) {//获取用户的微博头像----------------------startout.println("<image src=" + weiboUserInfoBean.getAvatar().getAvatarURL30() + "/><br/>");out.println("<image src=" + weiboUserInfoBean.getAvatar().getAvatarURL50() + "/><br/>");out.println("<image src=" + weiboUserInfoBean.getAvatar().getAvatarURL100() + "/><br/>");//获取用户的微博头像 ---------------------end//获取用户的生日信息 --------------------startout.println("<p>尊敬的用户,你的生日是: " + weiboUserInfoBean.getBirthday().getYear()+ "年" + weiboUserInfoBean.getBirthday().getMonth() + "月" +weiboUserInfoBean.getBirthday().getDay() + "日");//获取用户的生日信息 --------------------endStringBuffer sb = new StringBuffer();sb.append("<p>所在地:" + weiboUserInfoBean.getCountryCode() + "-" + weiboUserInfoBean.getProvinceCode() + "-" + weiboUserInfoBean.getCityCode()+ weiboUserInfoBean.getLocation());//获取用户的公司信息---------------------------startArrayList<Company> companies = weiboUserInfoBean.getCompanies();if (companies.size() > 0) {//有公司信息for (int i = 0, j = companies.size(); i < j; i++) {sb.append("<p>曾服役过的公司:公司ID-" + companies.get(i).getID() + " 名称-" +companies.get(i).getCompanyName() + " 部门名称-" + companies.get(i).getDepartmentName() + " 开始工作年-" +companies.get(i).getBeginYear() + " 结束工作年-" + companies.get(i).getEndYear());}} else {//没有公司信息}//获取用户的公司信息---------------------------endout.println(sb.toString());} else {out.println("很抱歉,我们没能正确获取到您的信息,原因是: " + weiboUserInfoBean.getMsg());}out.println("<p> end -----------------------------------利用获取到的accessToken,openid 去获取用户在微博的昵称等信息 ---------------------------- end </p>");}} catch (QQConnectException e) {}}
}

登录连接:

 <div class="form-group input-group" style="margin-top: 45px;"><a href="/qqlogin.do">请使用你的QQ账号登陆</a>
</div>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_715413.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从vancl看垂直商业网站的崛起

从vancl看垂直网站的崛起&#xff08;文&#xff1a;王英雄&#xff09;如果说2007年IT业内的几大事件&#xff0c;卖衬衣的卖火了&#xff0c;这肯定是2007年的重大事件之一。提起卖衬衣的&#xff0c;大家肯定会想到的是PPG&#xff0c;但我为什么不拿PPG做标题呐&#xff1f…

大型网站应用之海量数据和高并发解决方案总结一二

一、网站应用背景 开发一个网站的应用程序&#xff0c;当用户规模比较小的时候&#xff0c;使用简单的&#xff1a;一台应用服务器一台数据库服务器一台文件服务器&#xff0c;这样的话完全可以解决一部分问题&#xff0c;也可以通过堆硬件的方式来提高网站应用的访问性能&…

小白入门:大型网站技术架构负载均衡技术介绍及学习资源推荐

十年间&#xff0c;负载均衡的前沿技术层出不穷&#xff0c;令用户眼花缭乱。经常在技术网站、文档中出现的“四层负载均衡”、“七层负载均衡”字眼有什么含义?有什么区别?对客户网络有哪些不同的优化? 在大型的网站服务器集群中&#xff0c;负载均衡技术是必不可少的。使…

Flex SEO(Search engine optimization),让浏览器找到你的flash站点

Search engine optimistation 也就是让你的站点信息能被“搜索引擎”&#xff08;Google,baidu…&#xff09;搜索到。SEO总分两大类&#xff0c;white hats和black hats&#xff0c;简单讲black hats是一作弊的方法&#xff0c; 例如在meta标签中加一堆重复的关键词&#xff0…

unsharp mark 算法_Google SEO-BERT算法更新

一. BERT介绍BERT的全称为&#xff1a;Bidirectional Encoder Representations from Transformers&#xff0c;基于神经网络的自然语言处理预训练的技术。谷歌说BERT就像是一个超大的同义词系统。2019 年 10 月 25 日&#xff0c;Google 宣布 BERT 更新上线&#xff0c;正式成为…

有些网站打开一半空白_如何发一条空白的朋友圈

所谓空白的朋友圈就是一条看起来没有文字的朋友圈&#xff0c;因为发朋友圈的时候不输入文字是没法发送的。不可见字符是有文字内容的&#xff0c;只是人的肉眼看不见&#xff0c;所以相当于空白。不可见字符不可见字符就是零宽空格&#xff0c;见维基百科解释https://zh.wikip…

另类网站版式设计欣赏

另类网站版式设计欣赏 当你在创建一个新网站的时候&#xff0c;希望这些网站富有个性的版式设计能给你带来灵感。 Popmatik 这是Rob Leach设计制作的一个个人网站&#xff0c;这个网站用了一个瓶子的底图&#xff0c;网站的内容都在瓶子的这个包装纸上。 Digitalmash.com Digi…

大型网站架构系列:负载均衡详解(3)

大型网站架构系列&#xff1a;负载均衡详解&#xff08;3&#xff09; 原文:大型网站架构系列&#xff1a;负载均衡详解&#xff08;3&#xff09;本次分享大纲 软件负载均衡概述Ngnix负载均衡Lvs负载均衡Haproxy负载均衡本次分享总结一、软件负载均衡概述 硬件负载均衡性能优越…

基于Dockfile构建JAVA环境网站镜像

查看本地目录 [rootdocker tomcat]# ls apache-tomcat-8.5.16.tar.gz Dockerfile jdk-8u91-linux-x64.tar.gz server.xml [rootdocker tomcat]# vim Dockerfile FROM centos:7 MAINTAINER zhaochengcheng ADD jdk-8u91-linux-x64.tar.gz /usr/local ENV JAVA_HOME /usr/loca…

linux卸载服务器软件,linux卸载软件命令是什么_网站服务器运行维护,linux

win10系统提示需要提供管理员权限才能更改这些属性怎么办_网站服务器运行维护win10系统提示需要提供管理员权限才能更改这些属性的解决方法是&#xff1a;1、首先打开系统设置&#xff0c;进入【账户】选项&#xff1b;2、然后切换到【家庭和其他用户】&#xff0c;点击【更改账…

[目录] ASP.Net Core 搭建微服务网站

本项目采用ASP.Net Core微服务技术&#xff0c;搭建博客和Saas平台。 全文将围绕&#xff08;1&#xff09;设计模式 &#xff08;2&#xff09;敏捷开发 目的&#xff1a; 结构足够合理&#xff0c;代码足够优美&#xff0c;扩展性、可读性、易维护性做到最优。 以下目录…

网站建设流程-面向公司

1. 网站简明开发流程 简明开发流程是指假设网站开发的每个步骤都可以一次设计开发成功时的网站开发流程。   流程图如下&#xff1a; 2. 网站操作开发流程 网站操作开发流程是指假设网站开发的每个大的步骤都有可能产生未知问题时的网站开发流程。整个开发过程一般会有…

《大型网站技术架构》读书笔记二:大型网站架构模式

此篇已收录至《大型网站技术架构》读书笔记系列目录贴&#xff0c;点击访问该目录可获取更多内容。 一、分层 最常见的架构模式&#xff0c;将系统在横向维度上切分成几个部分&#xff0c;每个部分单一职责。网站一般分为三个层次&#xff1a;应用层、服务层和数据层&#xff0…

桌面风格的Web网站

天天记账网&#xff1a;http://www.365jizhang.com 超级牛牛无敌在线盯盘专家&#xff1a;http://www.googlook.net/stock/Stock.html

垂直网站的法宝——行业评测

垂直网站的法宝——行业评测 互联网垂直类网站在某个行业做久了对所从事的行业会很熟悉&#xff0c;继而从原来的纯粹提供资讯转变为更深入的行业信息&#xff0c;行业评测就是一个非常好的深入为网民服务的工具。 以下给大家举几个例子&#xff0c;给大家说说&#xff1a; 1、…

美国百年老报关门将转型新闻网站

两个月来&#xff0c;《西雅图邮讯报》员工最担心的事还是发生了。周一&#xff0c;美国出版巨头赫斯特集团宣布&#xff0c;该报将在17日发行最后一期报纸&#xff1b;然后转型为新闻网站。"今晚我们将最后一次出版报纸&#xff0c;"《西雅图邮讯报》总编兼发行人罗…

php 网站 seo,PHP网站怎么做SEO优化?

现在seo基本上已经是在广泛的应用了&#xff0c;php程序的企业网站也越来越多&#xff0c;其实我之前一直喜欢用asp的&#xff0c;但是发现很多国外的空间现在不支持asp&#xff0c;所以也就研究了一下php&#xff0c;网站建好&#xff0c;当然也想要有一个好的网站排名&#x…

推荐:学习人工智能(AI)的一些网站及教程资源

Python 深度学习库 Keras 发布官方中文文档https://keras.io/zh/这里有你需要了解的一切 今年1月&#xff0c;Keras作者、谷歌AI研究员Franois Chollet在推特上发出召唤&#xff1a;讲中文的Keras用户们&#xff0c;是否有人愿意帮忙一起搞个Keras文档的中文版&#xff1f; 一个…

2020十大最受欢迎的编程挑战网站【2020最新更新】

解决编码难题是提高学习编码技能的一种好方法。解决不同类型的挑战和难题可以帮助您成为更好的问题解决者&#xff0c;学习编程语言的复杂性&#xff0c;准备工作面试&#xff0c;学习新算法等等。 以下是一些受欢迎的编码挑战网站的列表&#xff0c;并简要说明了每个网站所提…

一个超火的网站“Omegle”

一个超火的网站“Omegle” 在美国有一个小网站突然暴红。这个网站叫「Omegle」(http://omegle.com/)&#xff0c;页面非常简单&#xff0c;实际就两个页面。它的首页就有一个很大的按钮&#xff0c;上面写着“开始聊天”按下去以后&#xff0c;它立刻将你和目前在线上的某位陌生…